Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

How the library works

Boost.Move is based on macros that are expanded to true rvalue references in C++0x compilers and emulated rvalue reference classes and conversion operators in C++03 compilers.

In C++03 compilers Boost.Move defines a class named ::boost::rv:

template <class T>
class rv : public T
{
   rv();
   ~rv();
   rv(rv const&);
   void operator=(rv const&);
};

which is convertible to the movable base class (usual C++ derived to base conversion). When users mark their classes as BOOST_MOVABLE_BUT_NOT_COPYABLE or BOOST_COPYABLE_AND_MOVABLE, these macros define conversion operators to references to ::boost::rv:

#define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\
   public:\
   operator ::boost::rv<TYPE>&() \
   {  return *static_cast< ::boost::rv<TYPE>* >(this);  }\
   operator const ::boost::rv<TYPE>&() const \
   {  return static_cast<const ::boost::rv<TYPE>* >(this);  }\
   private:\
   //More stuff...

BOOST_MOVABLE_BUT_NOT_COPYABLE also declares a private copy constructor and assignment. BOOST_COPYABLE_AND_MOVABLE defines a non-const copy constructor TYPE &operator=(TYPE&) that forwards to a const version:

#define BOOST_COPYABLE_AND_MOVABLE(TYPE)\
   public:\
   TYPE& operator=(TYPE &t)\
   {  this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;}\
   //More stuff...

In C++0x compilers BOOST_COPYABLE_AND_MOVABLE expands to nothing and BOOST_MOVABLE_BUT_NOT_COPYABLE declares copy constructor and assigment operator private.

When users define the BOOST_RV_REF overload of a copy constructor/assignment, in C++0x compilers it is expanded to a rvalue reference (T&&) overload and in C++03 compilers it is expanded to a ::boost::rv<T> & overload:

#define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \

When users define the BOOST_COPY_ASSIGN_REF overload, it is expanded to a usual copy assignment (const T &) overload in C++0x compilers and to a const ::boost::rv & overload in C++03 compilers:

#define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >&

As seen, in Boost.Move generates efficient and clean code for C++0x move semantics, without modifying any resolution overload. For C++03 compilers when overload resolution is performed these are the bindings:

The library does not define the equivalent of BOOST_COPY_ASSIGN_REF for copy construction (say, BOOST_COPY_CTOR_REF) because nearly all modern compilers implement RVO and this is much more efficient than any move emulation. move just casts TYPE & into ::boost::rv<TYPE> &.

Here's an example that demostrates how different rlvalue objects bind to ::boost::rv references in the presence of three overloads and the conversion operators in C++03 compilers:

#include <boost/move/core.hpp>
#include <iostream>

class sink_tester
{
   public: //conversions provided by BOOST_COPYABLE_AND_MOVABLE
   operator ::boost::rv<sink_tester>&()
      {  return *static_cast< ::boost::rv<sink_tester>* >(this);  }
   operator const ::boost::rv<sink_tester>&() const
      {  return *static_cast<const ::boost::rv<sink_tester>* >(this);  }
};

//Functions returning different r/lvalue types
      sink_tester    rvalue()       {  return sink_tester(); }
const sink_tester    const_rvalue() {  return sink_tester(); }
      sink_tester &  lvalue()       {  static sink_tester lv; return lv; }
const sink_tester &  const_lvalue() {  static const sink_tester clv = sink_tester(); return clv; }

//BOOST_RV_REF overload
void sink(::boost::rv<sink_tester> &)      { std::cout << "non-const rvalue catched" << std::endl; }
//BOOST_COPY_ASSIGN_REF overload
void sink(const ::boost::rv<sink_tester> &){ std::cout << "const (r-l)value catched" << std::endl; }
//Overload provided by BOOST_COPYABLE_AND_MOVABLE
void sink(sink_tester &)                   { std::cout << "non-const lvalue catched" << std::endl; }

int main()
{
   sink(const_rvalue());   //"const (r-l)value catched"
   sink(const_lvalue());   //"const (r-l)value catched"
   sink(lvalue());         //"non-const lvalue catched"
   sink(rvalue());         //"non-const rvalue catched"
   return 0;
}


PrevUpHomeNext