Last time, we discussed rvalue references. Rvalue references uniquely identify objects that can be safely moved from. In the move constructor below, rhs is an rvalue reference. It refers to an object, such as a temporary object, that will only exist for another moment before it disappears forever.
Texture( Texture&& rhs ) : // move ctor mpBits( std::move( rhs.mpBits ) ), mSize ( std::move( rhs.mSize ) ) { rhs.mpBits = nullptr; }
Now it’s time to discuss std::move() and why std::move() is important.
Recall that rhs is an rvalue reference. However, there’s a problem. It has a name. You can take the address of rhs. Hence, the variable rhs, in the context of the Texture() move constructor, is an lvalue! Let that sink in for a moment.
Despite the fact that the only way the Texture() move constructor could be invoked is if rhs was an rvalue at the point of the call, the compiler must treat rhs as an lvalue in the context of the actual move constructor, because it has a name. In order to inform the compiler to treat rhs as an rvalue, we must use std::move().
std::move() does one thing: tell the compiler to treat the incoming value as an rvalue reference. That’s it. std::move() has zero performance overhead. Think of it as the equivalent of a static cast, with the type deducted automatically:
mpBits( std::move( rhs.mpBits ) ); // equivalent to: mpBits( static_cast<t&&>( rhs.mpBits ) ); // where T is deducted from mpBits type
std::move() is provided by all C++11 implementations. It’s an inline function, so you can inspect the implementation for yourself should you care to witness reference collapsing and parameter deduction in action.
Takeaways:
- Use std::move() whenever you need to treat a named variable as an rvalue reference, such as within a move constructor or move assignment operator.
- std::move() is the equivalent of a cast. It has no performance penalty.
- std::move() is self-documenting. It indicates to your reader that you intend to move from the object in question.
Now we know about move constructors, rvalue references and std::move(). Next time we’ll put it altogether, compare move constructor to copy constructors, and extract some best practices.