I was binding some return value of a function to a const lvalue reference, but the object was deleted, before the lifetime of the const lvalue reference ended.
In the following example the Foo object is destroyed before the lifetime of foo
ends:
#include <iostream>
#include <string>
struct Foo
{
~Foo()
{
std::cout << "Foo destroyed: " << name << std::endl;
}
std::string name;
};
Foo&& pass_through(Foo&& foo)
{
return std::move(foo);
}
int main()
{
const Foo& foo = pass_through({"some string"});
std::cout << "before scope end" << std::endl;
}
The output is:
Foo destroyed: some string
before scope end
live on coliru: 1
I thought you can bind const T&
to anything. Is it bad practice to return T&&
and should returning by value be preferred?
I stumbled across this in the cpprestsdk here:
inline utility::string_t&& to_string_t(std::string &&s) { return std::move(s); }
https://github.com/Microsoft/cpprestsdk/blob/master/Release/include/cpprest/asyncrt_utils.h#L109
Very confusing, because the windows version of to_string_t
(dispatched by preprocessor macros) returned by value:
_ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s);
Edit:
Why does it work when passing the result of pass_through
to a function taking const Foo&
? The lifetime is extended in this case?
Foo(Foo&&) = default;
and it produced the same result. – Whatpass_through()
available. There's no way to know there's a link between the parameter RValue ref and the result RValue ref, and the lifetime of the temporaryFoo
must still be resolved at compile time, so the compiler has no choice but to be pessimistic about it. – Aftonagconst Foo& foo = Foo():
the lifetime of the temporary object created byFoo()
is extended, so it remains valid as long asfoo
does. That's called "lifetime extension". This question involves creating a temporaryFoo
object indirectly, and, as comments have said, that doesn't result in lifetime extension. – Vitiated