Question

Why reference can not capture temporary value while const reference and rvalue reference can capture and prolong object life. In other words while two first lines are legal but third not:

const string &a = string("a");
string &&b = string("b");
string &c = string("c"); // why illegal?
Was it helpful?

Solution

Quoting from N1377

Bjarne in his excellent text "The Design and Evolution of C++" discusses the motivation for prohibiting the binding of an rvalue to a non-const reference in section 3.7. The following example is shown:

void incr(int& rr) {rr++;}

void g()
{
    double ss = 1;
    incr(ss);
}

ss is not incremented, as a temporary int must be created to pass to incr(). The authors want to say right up front that we agree with this analysis 100%. Howard was even bitten by this "bug" once with an early compiler. It took him forever to track down what was going on (in that case it was an implicit conversion from float to double that created the temporary).

This rationale (for not binding rvalues to non-const (lvalue) references) held from the dawn of C++, up until C++11 (2011). However the same rationale does not apply to lvalue references to const:

It is "safe" to bind a temporary to an lvalue reference to const because the compiler will tell you if you accidentally make a "useless" modification to this temporary.

So why is it "safe" to bind an rvalue to an rvalue reference?

Again quoting from N1377:

Having said that, we would like to add: You don't ever want to bind a temporary to a non-const reference ... except when you do.

A non-const reference is not always intended to be an "out" parameter. Consider:

template <class T>
class auto_ptr
{
public:
    auto_ptr(auto_ptr& a);
    ...
};

The "copy" constructor takes a non-const reference named "a". But the modification of "a" is not the primary goal of this function. The primary goal is to construct a new auto_ptr by pilfering "a". If "a" happens to refer to an rvalue, this is not a logical error!

In summary, sometimes you want to modify an rvalue, and sometimes you don't. The different types of references allow the programmer to tell the compiler which situation they are in.

The bindings in your question are a logical conclusion of the bindings motivated by N1377.

The move semantics proposal did put effort into coming up with a solution that did not require language changes (i.e. the introduction of the rvalue reference). However library only solutions were unsatisfactory as the resulting syntax for building things like move constructors was overly complex.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top