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:

But what if we want to write AddItem function as a template? We can do this like this:

Ok, now this might be getting a little confusing, so let’s explain all of this.

First of all – this one template function can be deduced to accept both lvalues and rvalues. This creates a problem – as we’d like to move forward objects that came to us as an rvalue, but copy objects that come to us as an lvalue.

This is where we introduce the std::forward. In contrast to the std::move which is unconditional cast that will always cast to the rvalue, the std::forward is a conditional cast that will cast only when the item argument came to us as an rvalue.

In other words - std::forward allows to maintain the rvalue/lvalue nature of the passed argument in templated functions. Basically – if you have templated function you will probably use the std::forward to pass the value further. This is called the perfect forwarding.

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: