Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Composition or inheritance

For classes made up of other classes (via either composition or inheritance), the move constructor and move assignment can be easily coded using the boost::move function:

class Base
{
   BOOST_COPYABLE_AND_MOVABLE(Base)

   public:
   Base(){}

   Base(const Base &x) {/**/}             // Copy ctor

   Base(BOOST_RV_REF(Base) x) {/**/}      // Move ctor

   Base& operator=(BOOST_RV_REF(Base) x)
   {/**/ return *this;}                   // Move assign

   Base& operator=(BOOST_COPY_ASSIGN_REF(Base) x)
   {/**/ return *this;}                   // Copy assign

   virtual Base *clone() const
   {  return new Base(*this);  }

   virtual ~Base(){}
};

class Member
{
   BOOST_COPYABLE_AND_MOVABLE(Member)

   public:
   Member(){}

   // Compiler-generated copy constructor...

   Member(BOOST_RV_REF(Member))  {/**/}      // Move ctor

   Member &operator=(BOOST_RV_REF(Member))   // Move assign
   {/**/ return *this;  }

   Member &operator=(BOOST_COPY_ASSIGN_REF(Member))   // Copy assign
   {/**/ return *this;  }
};

class Derived : public Base
{
   BOOST_COPYABLE_AND_MOVABLE(Derived)
   Member mem_;

   public:
   Derived(){}

   // Compiler-generated copy constructor...

   Derived(BOOST_RV_REF(Derived) x)             // Move ctor
      : Base(boost::move(static_cast<Base&>(x))),
        mem_(boost::move(x.mem_)) { }

   Derived& operator=(BOOST_RV_REF(Derived) x)  // Move assign
   {
      Base::operator=(boost::move(static_cast<Base&>(x)));
      mem_  = boost::move(x.mem_);
      return *this;
   }

   Derived& operator=(BOOST_COPY_ASSIGN_REF(Derived) x)  // Copy assign
   {
      Base::operator=(static_cast<const Base&>(x));
      mem_  = x.mem_;
      return *this;
   }
   // ...
};

[Important] Important

Due to limitations in the emulation code, a cast to Base & is needed before moving the base part in the move constructor and call Base's move constructor instead of the copy constructor.

Each subobject will now be treated individually, calling move to bind to the subobject's move constructors and move assignment operators. Member has move operations coded (just like our earlier clone_ptr example) which will completely avoid the tremendously more expensive copy operations:

Derived d;
Derived d2(boost::move(d));
d2 = boost::move(d);

Note above that the argument x is treated as a lvalue reference. That's why it is necessary to say move(x) instead of just x when passing down to the base class. This is a key safety feature of move semantics designed to prevent accidently moving twice from some named variable. All moves from lvalues occur explicitly.


PrevUpHomeNext