Search code examples
c++pass-by-referencepass-by-value

Why would you ever take the copy of an object as a parameter to your function? Why are not const ref the default way of parameters?


As much as I enjoy C++ programming, there is one thing I really don't get. To me, it seems that the most common way of programming a function is like this:

some_function(a variable)
    do something according to the data in the variable

example:

bool match_name(const std::string& name)
{
    return this->name == name;
}

I find myself using const ref for 90% of all function parameters in my code (maybe I'm doing something wrong).

My question is: Why is a copy of the variable the "default" type of parameters? Why are not const ref the default?

Why not something like?:

void my_function(My_type object)      // <- const ref

void my_function(ref My_type object)  // <- ref (mutable)

void my_function(copy My_type object) // <- copy

Solution

  • C++ wants to be compatible with C, and since C uses value semantics by default, so does C++. It would be very inconsistent to take build-in types by value but other types by reference.

    However, passing by reference is not always better. The pointer indirection a reference causes generally makes it harder for the compiler to optimize code gen. In many cases, passing a type by value is still better than by ref. It depends on the type. The pointer indirection of references might cause a memory read, while passing by value allows the object to be passed in CPU registers. For example, a type like this:

    class Point {
    public:
        /* functions */
    private:
        int x;
        int y;
    };
    

    Should always be passed by value. It's just two integers. A reference might cause unneeded memory reads to get to the values.

    Also, sometimes you want to pass by value even if the type cannot be enregistered. So called "sink functions" for example that need to store the passed value perform better with values due to move semantics. Prime examples are constructros and setters:

    void SomeClass::setString(std::string s)
    {
        this->s_ = std::move(s);
    }
    

    Passing by reference in this case can incur extra copies. You can read up more on this online. A good starting point is this SO question:

    Are the days of passing const std::string & as a parameter over?