Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Can const lvalue References Refer to Mutable rvalue References?

In C++11 a const lvalue reference can be initialized with a mutable rvalue reference. The value referred to by the rvalue can then change producing a visible mutation to what the const lvalue is referring to. Here is an example:

int && rval = 3;
const int & lval = rval;

cout << "lval = " << lval << endl;
cout << "rval = " << rval << endl;

rval ++;

cout << "lval = " << lval << endl;

Output (from clang 3.2 and gcc 4.8.2 both with -std=c++11):

lval = 3
rval = 3
lval = 4

I would guess the reason for this is that the referent cannot be modified through the lvalue reference but it can be modified through the rvalue reference. But, I don't understand why a const lvalue is allowed to refer to a mutable object.

Can someone explain the rationale for this and give best practices for when dealing with such a situation. Also, are there other similar examples where constness can be subverted?

like image 786
user2141130 Avatar asked Jan 07 '14 21:01

user2141130


1 Answers

But, I don't understand why a const lvalue is allowed to refer to a mutable object

Having a const reference to something only means that you can't modify the object through that reference. It doesn't mean that nobody is allowed to change the object ever.

Let's say you have a function:

void f(Foo const& bar);

The function is declaring to the caller that it will not modify bar. That's it. Nothing more than that, nothing less than that. It says nothing about what happens to bar while f is executing (e.g. in another thread); the language doesn't have a way to express constraints like that.

One last bit here:

int && rval = 3;

rval is an lvalue. It has a name and can be on the left side of an assignment, as your code clearly demonstrates. The difference between an rvalue reference and an lvalue reference is that rvalue references can bind to rvalues -- not that they themselves are rvalues.

This is why given something like

void foo(unique_ptr<X>&& x)
{
    aVector.emplace_back(x);
}

does not compile. x is declared as an rvalue reference, but inside foo it has a name and can be on the left side of an assignment, and is an lvalue. Moving it into something else requires using move or similar:

void foo(unique_ptr<X>&& x)
{
    aVector.emplace_back(move(x)); // Ok
}
like image 185
Billy ONeal Avatar answered Nov 15 '22 07:11

Billy ONeal