tags:

views:

172

answers:

4

Consider the below.

#include <string>
using std::string;

string middle_name () {
    return "Jaan";
}

int main()
{
    string&& danger = middle_name();   // ?!
    return 0;
}

This doesn't compute anything, but it compiles without error and demonstrates something that I find confusing: danger is a dangling reference, isn't it?

+1  A: 

danger is a dangling reference, isn't it?

Not any more than if you had used a const &: danger takes ownership of the rvalue.

Konrad Rudolph
+10  A: 
sellibitze
Excellent example of well-intentioned `move`-ing gone awry!
Potatoswatter
@sellibitze would `string` be ok?
KitsuneYMG
@kts: No. It wouldn't even compile because you can't initialize a non-const lvalue reference with an rvalue expression. If you write `string const` it won't work either. It'll compile but `danger` will be a dangling reference.
sellibitze
Is there an intuition for why this requires _pure_ rvalues? The xvalue case seems perfectly reasonable...
Andres Jaan Tack
@Andres: I tried to explain this in the answer. Only when the initializer is a pure rvalue the compiler knows exactly what the to-be-initialized reference will refer to. In this case, the correct temporary's life-time can and will be extended easily. If the initializer itself is a reference you don't really know *in general* what object exactly it refers to. `std::move` doesn't mean anything to the compiler. The information that the result of std::move refers to the same object is not preserved in the function's type.
sellibitze
@sellibitze That makes sense! A referenced object's lifetime can have any kind of lifetime, where a pure rvalue's lifetime is easily predicted and thus trivially extended.
Andres Jaan Tack
A: 

I'm not sure what you're doing with &&, but your compiler really ought to produce a warning in that case. You should only store a reference to a temporary if the reference is const. The article sellibitze linked (This one) says as much. Storing a non-const reference to a temporary is officially undefined.

Steve
It's C++0x, he has rvalue references. The fact that it's tagged C++0x was the hint.
DeadMG
The article was older than C++0x's rvalue references. The rule gets extended to rvalue references as well. Still, the initializer has to be a (pure) rvalue.
sellibitze
+3  A: 

rvalue references bind to rvalues. An rvalue is either a prvalue or an xvalue [explanation]. Binding to the former never creates a dangling reference, binding to the latter might. That's why it's generally a bad idea to choose T&& as the return type of a function. std::move is an exception to this rule.

T&  lvalue();
T   prvalue();
T&& xvalue();

T&& does_not_compile = lvalue();
T&& well_behaved = prvalue();
T&& problematic = xvalue();
FredOverflow
+1 You're right, it's a good rule of thumb not to write functions that return rvalue references. std::move and std::forward are the obvious exceptions.
sellibitze