Rvalue references are one of the biggest feature introduced to the c++11, but I found it rather difficult to understand and to find a usage for them. It was the issue which was very similar to the understanding c++ traits I had. Now, I’d like to write down all what I’ve learned, in order to remember it better and to share the way I understand it the best. This article is a very quick introduce to why we need rvalue references and why they are awesome!

Rvalue vs lvalue

Long story short: Lvalue is a value that residents in a memory. It has a name and we can take an address to it. Rvalue is not an lvalue, it’s temporary.

Lvalue reference vs rvalue reference

To get a reference to an lvalue we use & operand. To get a reference to an rvalue we use && operand.

When do we use rvalue references?

We use them to detect if the function argument has been passed by an lvalue or rvalue. Consider we have a class Room that stores Items. For future use, let the Item contains some data.

Now you can add Items to Room:

Without a function with rvalue reference as an argument the code would work as well. But we wouldn’t know if the item has been added by lvalue or rvalue.

What does it give us?

It gives us information if, when adding an item, we must copy all of it’s data or simply move. The problem with previous versions of c++, without rvalue references, is that when we run such code as:

it runs an Item class constructor, then copy data to the vector and destroys the temporary object. The copy step is just a waste of resources, when we can simply pass a pointer to the data. This is why, next to the copy constructor, we introduce a move constructor!

std::move

You can force moving objects by using the std::move function, which casts the object to an rvalue reference:

Only remember, that after this operation the item is no longer valid here! We’ve just moved it somewhere else.

Also – remember that std::move doesn’t guarantee that the item will be moved. For example – if the item is const, the move will fallback to copy.

Perfect forwarding

We are almost done, but there is something wrong with the code we’ve just wrote. You might notice, that even if we run AddItem function with the rvalue reference as the argument the item is added to the vector by copying, not moving. Why is that?

This is because the Item&& item is an lvalue! It has a name and we can get an address to it. That’s why when passed to push_back it goes to a copy constructor. To pass the arguments through to another function whilst retaining the rvalue nature simply use the move cast. The fixed AddItem function should looks like this:

We can optimize the Item class and write only one function like this:

Ok, this might be getting a little confusing. First of all – the new function std::forward is a conditional cast to rvalue reference, where the std::move is an unconditional cast. This means, that if the T&& Item (which is an lvalue) was passed to the AddItem function as an lvalue – nothing will happen. But if it was passed to the AddItem function as an rvalue – the std::forward will cast the Item to the rvalue reference.

So use std::move when you know for sure that the argument was passed as the rvalue reference and use std::forward when you don’t know that (usually always when the function or class is a template).

Further readings

And that’s all. The whole idea of rvalue references is to provide much more optimal way to pass complex structures through containers. For more information go to these articles: