At GDC this year, my presentation covered move construction, a new fast method of constructing objects in C++11. Here’s how it works. Up until C++11, whenever you created a new object from an existing object, you copied the object by using a copy constructor. The copy constructor looks something like this:
Texture( const Texture& rhs ) {
mSize = rhs.mSize;
mpBits = new unsigned long [mSize];
memcpy( mpBits, rhs.mpBits, mSize );
}
The problem that move constructors solve is situations like this:
Texture x( Texture(...) ); // copy from a temporary
In the scenario above, we create a temporary texture object, then we create another texture object x, copy the temporary to x, then tear down the temporary object. That’s a lot of work when it’s very clear to us as programmers that it would be more efficient to simply swap out the guts of the temporary object directly into x. That’s exactly what move constructors allow. Here’s a move constructor in C++11:
Texture( Texture&& rhs ) : // move ctor
mpBits( std::move( rhs.mpBits ) ),
mSize ( std::move( rhs.mSize ) )
{
rhs.mpBits = nullptr;
}
The move constructor allows us to do exactly what we want: eviscerate the guts from rhs. We leave rhs in a known good state. It is still a C++ object, after all — but one that will immediately be destroyed because it’s a temporary.
As a result, we can gain massive speed improvements. In this scenario, we avoid an extra allocation, a memcpy, and a deallocation. We also avoid having to hold two textures in memory at the same time.
You might have noticed something a little strange, however. The notation for a move constructor uses an unfamiliar && notation, and it passes rhs by non-const. We’ll cover this new C++11 notation next time.
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().