I heard a recent talk by Herb Sutter who suggested that the reasons to pass std::vector
and std::string
by const &
are largely gone. He suggested that writing a function such as the following is now preferable:
std::string do_something ( std::string inval )
{
std::string return_val;
// ... do stuff ...
return return_val;
}
I understand that the return_val
will be an rvalue at the point the function returns and can therefore be returned using move semantics, which are very cheap. However, inval
is still much larger than the size of a reference (which is usually implemented as a pointer). This is because a std::string
has various components including a pointer into the heap and a member char[]
for short string optimization. So it seems to me that passing by reference is still a good idea.
Can anyone explain why Herb might have said this?
Best Answer
The reason Herb said what he said is because of cases like this.
Let's say I have function
A
which calls functionB
, which calls functionC
. AndA
passes a string throughB
and intoC
.A
does not know or care aboutC
; allA
knows about isB
. That is,C
is an implementation detail ofB
.Let's say that A is defined as follows:
If B and C take the string by
const&
, then it looks something like this:All well and good. You're just passing pointers around, no copying, no moving, everyone's happy.
C
takes aconst&
because it doesn't store the string. It simply uses it.Now, I want to make one simple change:
C
needs to store the string somewhere.Hello, copy constructor and potential memory allocation (ignore the Short String Optimization (SSO)). C++11's move semantics are supposed to make it possible to remove needless copy-constructing, right? And
A
passes a temporary; there's no reason whyC
should have to copy the data. It should just abscond with what was given to it.Except it can't. Because it takes a
const&
.If I change
C
to take its parameter by value, that just causesB
to do the copy into that parameter; I gain nothing.So if I had just passed
str
by value through all of the functions, relying onstd::move
to shuffle the data around, we wouldn't have this problem. If someone wants to hold on to it, they can. If they don't, oh well.Is it more expensive? Yes; moving into a value is more expensive than using references. Is it less expensive than the copy? Not for small strings with SSO. Is it worth doing?
It depends on your use case. How much do you hate memory allocations?