Move Construction, part II

Last time, I provided an introduction to move construction, a new method of constructing objects in C++11. The move constructor looked like this:

Texture( Texture&& rhs ) : // move ctor
   mpBits( std::move( rhs.mpBits ) ),
   mSize ( std::move( rhs.mSize  ) )
   rhs.mpBits = nullptr;

The && notation is a little strange: two ampersands in a row. This is not a logical AND. This notation is called an rvalue reference. Rvalue references are a new feature of C++11, and they are at the core of enabling move semantics.

Before we can talk about rvalue references, we first need to talk about rvalues. In C++11, every expression is either an lvalue or an rvalue. I like to think of lvalues as Located in Memory, hence: L-values. Rvalues are not located in memory. They don’t have names, and you can’t take their address. Rvalues are ephemeral. They exist for a brief period of time, typically as temporary objects. Here are some examples:

int x;

x is an lvalue. It has a name. It lives in memory. You can take its address.

int x = 1+2;

1+2 is an rvalue. It doesn’t have a name. It doesn’t live in memory. You can’t take its address.

foo( x );

x is an lvalue. It lives in memory and you can take its address.

foo( bar() );

bar() is a default constructor that returns a bar object. That object is an rvalue. It does not have a name and does not reside in memory. You cannot take its address. In fact, bar() is a classic example of a moveable object. It is a temporary object that does not live beyond the lifetime of foo(). The result of bar() could be “moved” into foo() rather than being copied, if there was some way for the compiler to know that bar() was a moveable object.

Rvalue references to the rescue. Before C++11, a T& represented both lvalue and rvalue references. We simply called a T& a reference. In C++11, there are now two types of references. In C++11, T& is an lvalue reference, and T&& is an rvalue reference.

What does this mean? With C++11, we now have a way of uniquely identifying objects which can be safely moved from. Rvalue references uniquely identify those objects, because rvalue references bind to rvalue expressions and lvalue references bind to lvalue expressions.

Texture( Texture&& rhs ) : // move ctor
   mpBits( std::move( rhs.mpBits ) ),
   mSize ( std::move( rhs.mSize  ) )
   rhs.mpBits = nullptr;

In the move constructor, we are guaranteed that rhs represents an object that can be safely moved from. Very sweet. The next challenge is understanding exactly what it means to move from an object rather than copy from an object. We’ll cover that next time.

This entry was posted in C++. Bookmark the permalink.

One Response to Move Construction, part II

  1. pkisensee says:

    Scott Meyers noted that although my move constructor is technically correct because the data is all PODs, it would be prudent to encourage a pattern that you’re going to see in later posts. Hence, I’ve updated the move constructor code to use std::move().

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s