Saturday 21 October 2017

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

itemprop="text">

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?


itemprop="text">
class="normal">Answer



The reason
Herb said what he said is because of cases like
this.



Let's say I have function
A which calls function B, which calls
function C. And A passes a string
through B and into C.
A does not know or care about C; all
A knows about is B. That is,
C is an implementation detail of
B.



Let's say that A is
defined as follows:



void
A()

{

B("value");
}


If
B and C take the string by const&, then it looks something
like this:



void B(const
std::string &str)
{

C(str);

}

void C(const std::string
&str)
{
//Do something with `str`. Does not store
it.
}


All
well and good. You're just passing pointers around, no copying, no moving, everyone's
happy. C takes a const& 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.



void C(const
std::string &str)
{
//Do something with `str`.
m_str
=
str;
}


Hello,
copy constructor and potential memory allocation (ignore the href="https://stackoverflow.com/questions/10315041/meaning-of-acronym-sso-in-the-context-of-stdstring">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 why C 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 causes
B 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 on
std::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?



No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...