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(){}

   // Compiler-generated copy constructor...

   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);  }
};

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

BOOST_COPY_ASSIGN_REF(classname) macro is not needed if the 'Non-optimized' mode is selected, the usual const classname & overaload would be fine. See Two emulation modes for more details about pros/cons of this emulation mode.

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