One of the greatest features of the C++11 standard is rvalue references. This feature allows us to modify temporary objects, stealing resources from them. As you can guess, the C++03 standard has no rvalue references, but using the Boost.Move
library, you can write a portable code that emulates them.
It is highly recommended that you are at least familiar with the basics of C++11 rvalue references.
- Imagine that you have a class with multiple fields, some of which are standard library containers:
namespace other { class characteristics{}; } struct person_info { std::string name_; std::string second_name_; other::characteristics characteristic_; // ... };
- It is time to add the move assignment and move constructors to it! Just remember that in the C++03 standard library, containers have neither move operators nor move constructors.
- The correct implementation of the move assignment is the same move constructing an object and swapping it with
this
. The correct implementation of the move constructor is close to the default construct andswap
. So, let's start with theswap
member function:
#include <boost/swap.hpp> void person_info::swap(person_info& rhs) { name_.swap(rhs.name_); second_name_.swap(rhs.second_name_); boost::swap(characteristic_, rhs.characteristic_); }
- Now, put the following macro in the
private
section:
BOOST_COPYABLE_AND_MOVABLE(person_info)
- Write a copy constructor.
- Write a copy assignment, taking the parameter as:
BOOST_COPY_ASSIGN_REF(person_info)
.
- Write a
move
constructor and a move assignment, taking the parameter asBOOST_RV_REF(person_info)
:
struct person_info { // Fields declared here // ... private: BOOST_COPYABLE_AND_MOVABLE(person_info) public: // For the simplicity of example we will assume that // person_info default constructor and swap are very // fast/cheap to call. person_info(); person_info(const person_info& p) : name_(p.name_) , second_name_(p.second_name_) , characteristic_(p.characteristic_) {} person_info(BOOST_RV_REF(person_info) person) { swap(person); } person_info& operator=(BOOST_COPY_ASSIGN_REF(person_info) person) { person_info tmp(person); swap(tmp); return *this; } person_info& operator=(BOOST_RV_REF(person_info) person) { person_info tmp(boost::move(person)); swap(tmp); return *this; } void swap(person_info& rhs); };
- Now, we have a portable fast implementation of the move assignment and move construction operators of the
person_info
class.
Here is an example of how the move assignment can be used:
int main() { person_info vasya; vasya.name_ = "Vasya"; vasya.second_name_ = "Snow"; person_info new_vasya(boost::move(vasya)); assert(new_vasya.name_ == "Vasya"); assert(new_vasya.second_name_ == "Snow"); assert(vasya.name_.empty()); assert(vasya.second_name_.empty()); vasya = boost::move(new_vasya); assert(vasya.name_ == "Vasya"); assert(vasya.second_name_ == "Snow"); assert(new_vasya.name_.empty()); assert(new_vasya.second_name_.empty()); }
The Boost.Move
library is implemented in a very efficient way. When the C++11 compiler is used, all the macros for rvalues emulation are expanded to C++11-specific features otherwise (on C++03 compilers), rvalues are emulated.
Have you noticed the boost::swap
call? It is a really helpful utility function, which first searches for a swap
function in the namespace of a variable (in our example, it's namespace other::
), and if there is no matching swap function, it uses the std::swap
.
- More information about emulation implementation can be found on the Boost website and in the sources of the
Boost.Move
library at http://boost.org/libs/move. - The
Boost.Utility
library is the one that containsboost::swap
, and it has many useful functions and classes. Refer to http://boost.org/libs/utility for its documentation. - The Initializing a base class by the member of derived recipe in Chapter 2, Managing Resources.
- The Making a noncopyable class recipe.
- In the Making a noncopyable but movable class recipe, there is more info about
Boost.Move
and some examples on how we can use the movable objects in containers in a portable and efficient way.