The reason why this fails is because it essentially compiles to the following under the hood.
Foo o(std::string("wurd"));
In this case the Foo
value is taking a reference to a temporary object which is deleted after the constructor completes. Hence it's holding onto a dead value. The second version works because it's holding a reference to a local which has a greater lifetime than the Foo
instance.
To fix this change the memebr from being a const std::string&
to a const std::string
.
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 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?
Best Answer
Yes.
The problem with
std::string_view
is that it doesn't remember if it points to a null-terminated string or not.If you're writing a wrapper for a C api that uses null-terminated strings, you would have to constantly copy your
std::string_view
s intostd::string
s to make sure you have null-terminators.