Question

Is it legal to have a rvalue refrence of a lvalue reference ?

Considering the following example, is there a difference between the two cases in the final rvalueRef in term of what it refer to or type (or others things)?

Type& ref = GetReference()
Type&& rvalueRef = std::move(ref)

vs

Type value = GetValue()
Type&& rvalueRef = std::move(value)
Was it helpful?

Solution

Both code is correct and 100% legal in C++. There is a difference only in the sense that in the first case a reference is moved (or better say, capable of being moved if appropriate destination is used) and in second case, it is the copy (see the example below for clarification on this).

Note that std::move does NOT actually move the object. It only casts the object into a rvalue reference type. That is all.

Also note that in both cases, rvalueRef is still an lvalue — an object which has a name (i.e an identifier to refer to) is never an rvalue. So if you don't actually move it using std::move (or using explicit cast) again, then there is no difference at all.

Here is a concrete example:

//given function
std::string& GetReference(); 
std::string  GetValue(); 

//target function
void f(std::string param); 

And your code follows:

std::string& ref = GetReference();
std::string&& rvalueRef = std::move(ref);

std::string value = GetValue()
std::string&& rvalueCopy = std::move(value); //named changed

till now NO DIFFERENCE at all.

But if you do this:

f(std::move(rvalueRef));  //actual object returned from GetReference is moved!
f(std::move(rvalueCopy)); //only a copy is moved.

The actual object is moved in the first case, and in the second case, the copy is moved. It doesn't make any difference at all if you do this:

f(std::move(GetReference()));  //actual object returned from GetReference is moved!
f(std::move(GetValue()));      //only a copy is moved.

So you see, in your code, there is no difference because there is NO ACTUAL MOVE at all. Only cast is there. To have an actual move, there should be an appropriate target type which could invoke move-constructor or move-assignment! In your case, there is NO invocation of either.

OTHER TIPS

Q. Is it legal to have a rvalue refrence of a lvalue reference?

That's not really the question you are asking. The question you are really asking is this:

Q. Is it legal to cast an lvalue reference to an rvalue reference?

The answer is yes. std::move just casts its argument to an rvalue reference, which is always legal. The overall correctness of what you are doing depends on what you then do with the result of std::move. There is nothing wrong with your example code.

Q. Is there a difference between these two cases?

// case 1                             // case 2
Type& ref = GetReference();           Type value = GetValue();
f(std::move(ref));                    f(std::move(value));

The only difference is that in case 1, ref is a reference to the object returned by GetReference(), but in case 2, value is a copy of the object returned by GetValue().

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