Implementing copyable and movable classes

| Home | Libraries | People | FAQ | More

## Implementing copyable and movable classes

### Copyable and movable classes in C++0x

Consider a simple handle class that owns a resource and also provides copy semantics (copy constructor and assignment). For example a `clone_ptr` might own a pointer, and call `clone()` on it for copying purposes:

    template <class T>
    class clone_ptr
    {
       private:
       T* ptr;

       public:
       // construction
       explicit clone_ptr(T* p = 0) : ptr(p) {}

       // destruction
       ~clone_ptr() { delete ptr; }

       // copy semantics
       clone_ptr(const clone_ptr& p)
          : ptr(p.ptr ? p.ptr->clone() : 0) {}

       clone_ptr& operator=(const clone_ptr& p)
       {
          if (this != &p)
          {
             T *p = p.ptr ? p.ptr->clone() : 0;
             delete ptr;
             ptr = p;
          }
          return *this;
       }

       // move semantics
       clone_ptr(clone_ptr&& p)
          : ptr(p.ptr) { p.ptr = 0; }

       clone_ptr& operator=(clone_ptr&& p)
       {
          if(this != &p)
          {
             std::swap(ptr, p.ptr);
             delete p.ptr;
             p.ptr = 0;
          }
          return *this;
       }

       // Other operations...
    };

`clone_ptr` has expected copy constructor and assignment semantics, duplicating resources when copying. Note that copy constructing or assigning a `clone_ptr` is a relatively expensive operation:

    clone_ptr<Base> p1(new Derived());
    // ...
    clone_ptr<Base> p2 = p1;  // p2 and p1 each own their own pointer

`clone_ptr` is code that you might find in today's books on C++, except for the part marked as `move semantics`. That part is implemented in terms of C++0x `rvalue references`. You can find some good introduction and tutorials on rvalue references in these papers:

- A Brief Introduction to Rvalue References
- Rvalue References: C++0x Features in VC10, Part 2

When the source of the copy is known to be a `rvalue` (e.g.: a temporary object), one can avoid the potentially expensive `clone()` operation by pilfering source's pointer (no one will notice!). The move constructor above does exactly that, leaving the rvalue in a default constructed state. The move assignment operator simply does the same freeing old resources.

Now when code tries to copy a rvalue `clone_ptr`, or if that code explicitly gives permission to consider the source of the copy a rvalue (using `boost::move`), the operation will execute much faster.

    clone_ptr<Base> p1(new Derived());
    // ...
    clone_ptr<Base> p2 = boost::move(p1);  // p2 now owns the pointer instead of p1
    p2 = clone_ptr<Base>(new Derived());   // temporary is moved to p2
    }

### Copyable and movable classes in portable syntax for both C++03 and C++0x compilers

Many aspects of move semantics can be emulated for compilers not supporting `rvalue references` and Boost.Move offers tools for that purpose. With Boost.Move we can write `clone_ptr` so that it will work both in compilers with rvalue references and those who conform to C++03. You just need to follow these simple steps:

- Put the following macro in the private section: `BOOST_COPYABLE_AND_MOVABLE(classname)`
- Leave copy constructor as is.
- Write a copy assignment taking the parameter as `BOOST_COPY_ASSIGN_REF(classname)`
- Write a move constructor and a move assignment taking the parameter as `BOOST_RV_REF(classname)`

Let's see how are applied to `clone_ptr`:

    template <class T>
    class clone_ptr
    {
       private:
       // Mark this class copyable and movable
       BOOST_COPYABLE_AND_MOVABLE(clone_ptr)
       T* ptr;

       public:
       // Construction
       explicit clone_ptr(T* p = 0) : ptr(p) {}

       // Destruction
       ~clone_ptr() { delete ptr; }

       clone_ptr(const clone_ptr& p) // Copy constructor (as usual)
          : ptr(p.ptr ? p.ptr->clone() : 0) {}

       clone_ptr& operator=(BOOST_COPY_ASSIGN_REF(clone_ptr) p) // Copy assignment
       {
          if (this != &p){
             T *tmp_p = p.ptr ? p.ptr->clone() : 0;
             delete ptr;
             ptr = tmp_p;
          }
          return *this;
       }

       //Move semantics...
       clone_ptr(BOOST_RV_REF(clone_ptr) p)            //Move constructor
          : ptr(p.ptr) { p.ptr = 0; }

       clone_ptr& operator=(BOOST_RV_REF(clone_ptr) p) //Move assignment
       {
          if (this != &p){
             delete ptr;
             ptr = p.ptr;
             p.ptr = 0;
          }
          return *this;
       }
    };

Question: What about types that don't own resources? (E.g. `std::complex`?)

No work needs to be done in that case. The copy constructor is already optimal.