Emulation limitations

| Home | Libraries | People | FAQ | More

## Emulation limitations

Like any emulation effort, the library has some limitations users should take in care to achieve portable and efficient code when using the library with C++03 conformant compilers:

### Initializing base classes

When initializing base classes in move constructors, users must cast the reference to a base class reference before moving it or just use `BOOST_MOVE_BASE`. Example:

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

or

    Derived(BOOST_RV_REF(Derived) x)             // Move ctor
       : Base(BOOST_MOVE_BASE(Base, x))
         //...

If casting is not performed the emulation will not move construct the base class, because no conversion is available from `BOOST_RV_REF(Derived)` to `BOOST_RV_REF(Base)`. Without the cast or `BOOST_MOVE_BASE` we might obtain a compilation error (for non-copyable types) or a less-efficient move constructor (for copyable types):

    //If Derived is copyable, then Base is copy-constructed.
    //If not, a compilation error is issued
    Derived(BOOST_RV_REF(Derived) x)             // Move ctor
       : Base(boost::move(x))
         //...

### Template parameters for perfect forwarding

The emulation can't deal with C++0x reference collapsing rules that allow perfect forwarding:

    //C++0x
    template<class T>
    void forward_function(T &&t)
    {  inner_function(std::forward<T>(t); }

    //Wrong C++03 emulation
    template<class T>
    void forward_function(BOOST_RV_REF<T> t)
    {  inner_function(boost::forward<T>(t); }

In C++03 emulation BOOST_RV_REF doesn't catch any const rlvalues. For more details on forwarding see Constructor Forwarding chapter.

### Binding of rvalue references to lvalues

The first rvalue reference proposal allowed the binding of rvalue references to lvalues:

    func(Type &&t);
    //....

    Type t;  //Allowed
    func(t)

Later, as explained in Fixing a Safety Problem with Rvalue References this behaviour was considered dangerous and eliminated this binding so that rvalue references adhere to the principle of type-safe overloading: Every function must be type-safe in isolation, without regard to how it has been overloaded

Boost.Move can't emulate this type-safe overloading principle for C++03 compilers:

    //Allowed by move emulation
    movable m;
    BOOST_RV_REF(movable) r = m;

### Assignment operator in classes derived from or holding copyable and movable types

The macro `BOOST_COPYABLE_AND_MOVABLE` needs to define a copy constructor for `copyable_and_movable` taking a non-const parameter in C++03 compilers:

    //Generated by BOOST_COPYABLE_AND_MOVABLE
    copyable_and_movable &operator=(copyable_and_movable&){/**/}

Since the non-const overload of the copy constructor is generated, compiler-generated assignment operators for classes containing `copyable_and_movable` will get the non-const copy constructor overload, which will surely surprise users:

    class holder
    {
       copyable_and_movable c;
    };

    void func(const holder& h)
    {
       holder copy_h(h); //<--- ERROR: can't convert 'const holder&' to 'holder&'
       //Compiler-generated copy constructor is non-const:
       // holder& operator(holder &)
       //!!!
    }

This limitation forces the user to define a const version of the copy assignment, in all classes holding copyable and movable classes which might be annoying in some cases.

An alternative is to implement a single `operator =()` for copyable and movable classes using "pass by value" semantics:

    T& operator=(T x)    // x is a copy of the source; hard work already done
    {
       swap(*this, x);  // trade our resources for x's
       return *this;    // our (old) resources get destroyed with x
    }

However, "pass by value" is not optimal for classes (like containers, strings, etc.) that reuse resources (like previously allocated memory) when x is assigned from a lvalue.