It depends on what you do with the string afterwards.
If your question is is my code correct? then yes is it.
From [dcl.fct.default]/2
[ Example: The declaration
void point(int = 3, int = 4);
declares a function that can be called with zero, one, or two
arguments of type int. It can be called in any of these ways:
point(1,2); point(1); point();
The last two calls are equivalent to point(1,4)
and point(3,4)
,
respectively. — end example]
So your code is effectively equivalent to:
const std::string& s1 = foo(std::string(""));
std::string s2 = foo(std::string(""));
All your code is correct, but there is no reference lifetime extension in any of these cases, since the return type is a reference.
Since you call a function with a temporary, the lifetime of the returned string won't extend the statement.
const std::string& s1 = foo(std::string("")); // okay
s1; // not okay, s1 is dead. s1 is the temporary.
Your example with s2
is okay since you copy (or move) from the temporary before the end of the satement. s3
has the same problem than s1
.