Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can you indirectly bind an rvalue to an lvalue reference but not directly?

Tags:

c++

c++11

c++14

From what I've read and seen you cannot bind an expression that is an rvalue to an lvalue reference. What I have seen however is that you can bind an rvalue to an rvalue reference and since a named rvalue reference is inherently an lvalue, you can bind it to an lvalue reference. What is the reason behind disallowing binding an rvalue to an lvalue reference. Is it for optimization purposes?

Take this example:

#include <iostream>

using std::cout;

void bar ( int& b ) {

    cout << "bar " << b << "\n";
    b = 3;
}

void foo ( int&& a ) {

    cout << a << "\n";
    bar(a);
    cout << a << "\n";
}

int main ( int argc, char ** argv ) {

    foo(1);
}
like image 203
edaniels Avatar asked Oct 14 '14 20:10

edaniels


People also ask

Can lvalue reference bind rvalue?

By default, the compiler cannot bind a non-const or volatile lvalue reference to an rvalue.

What is the difference between lvalue and rvalue references?

“l-value” refers to a memory location that identifies an object. “r-value” refers to the data value that is stored at some address in memory. References in C++ are nothing but the alternative to the already existing variable.

What is the point of an rvalue reference?

Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.

How do you pass rvalue reference to a function?

If you want pass parameter as rvalue reference,use std::move() or just pass rvalue to your function.


2 Answers

It's a fundamental rule of C++ and it prevents bugs:

int foo();

int& x = 3;      // whoops
int& y = foo();  // whoops (sometimes)

"Rvalue references" (a set of types; not to be confused with actual rvalues) were created at least in part so that you can still do this if you really want to:

int&& x = 3;     // oh, go on then *sigh*
int&& y = foo(); // you'd better be sure!

In the previous examples, I bind (or attempt to bind) objects "referenced" by an rvalue expression to a reference.

Now, I shall bind the object named by an lvalue expression to a reference:

int i = foo();

int& x = i;      // no problem michael

And to make sure that you really meant to obtain an rvalue reference from an lvalue expression, introducing the incredibly poorly-named std::move:

int&& x = std::move(i);  // doesn't move anything

These later rules came much, much later than the original, fundamental rule that has doubtless prevented many bugs over the past twenty years.

Note that Visual Studio has historically accepted T& x = bar() where T is a user-defined type; go figure.

like image 179
Lightness Races in Orbit Avatar answered Sep 17 '22 14:09

Lightness Races in Orbit


What is the reason behind disallowing binding an rvalue to an lvalue reference?

No answer to this question can be complete without a reference to the invaluable and distinguished source, The Design and Evolution of C++ by Bjarne Stroustrup.

In section 3.7 Bjarne writes:

I made one serious mistake, though, by allowing a non-const reference to be initialized by a non-lvalue. For example:

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

void g()
{
    double ss = 1;
    incr(ss);    // note: double passed, int expected
                 // (fixed: error in Release 2.0)
}

Because of the difference in type the int& cannot refer to the double passed so a temporary was generated to hold an int initialized by ss's value. Thus incr() modified the temporary, and the result wasn't reflected back to the calling function.

I highly recommend The Design and Evolution of C++ for understanding many of the "why questions" one might have, especially regarding the rules that were laid down prior to the C++98 standard. It is an informative and fascinating history of the language.

like image 43
Howard Hinnant Avatar answered Sep 17 '22 14:09

Howard Hinnant