Your code is illegal; non-const lvalue references may not bind to rvalues. There's not really a good reason behind this, it's just a language rule that was introduced very early on in C++'s history.
MSVC used to (maybe still does) allow this binding, I can't comment on how MSVC implements it.
You can bind to other reference types though:
std::string const &a = foo(); // (1)
std::string&& b = foo(); // (2)
In case (2), b
binds directly to the return value object, which has its lifetime extended to match b
's lifetime. Note: no "move" operation occurs here, it is just binding a reference.
In case (1), conceptually, a temporary of type const std::string
is initialized from the return value, and that temporary has its lifetime extended to match a
's lifetime. In practice this copy will be elided. your code will behave as if the reference bound directly to the return value.
Generally speaking, you should use value semantics. std::string c = foo();
is the safest option. Because of copy elision, it is not any less efficient than the reference options.
The main danger with the reference option is that if the function were changed to return a reference, then a
or b
may become a dangling reference.