Boost logo

Boost :

From: Joe Gottman (jgottman_at_[hidden])
Date: 2005-02-14 20:35:31


   I just discovered that optional<T> is not safe under self-assignment.
Consider the following code fragment:

    boost::optional<long> x(1); //At this point x is initialized and *x == 1
    x = x; //x should be unchanged, but instead x is now uninitialized

Optional's assignment operator looks like

optional& operator= ( optional const& rhs )
      {
        this->assign( rhs ) ;
        return *this ;
      }

and assign is defined by

void assign ( argument_type val )
      {
        destroy();
        construct(val);
      }

Thus, if (this == &rhs) in operator=(), any value held by rhs will be
destroyed.

I can see two possible fixes for this. the first is to put an "if (this !=
&rhs) " around the call to assign in operator=(). This is simplest, but it
slows the code down in order to protect against a very rare situation. The
other is to rewrite assign as follows:

void assign(argument_type val)
{
    if (m_initialized) {
        get() = val; // call assignment operator
    } else {
        construct(val); //call copy constructor
    }
    return *this;
}

This makes optional self-assignment safe. It has the added advantage that
is T's assignment operator has the strong exception safety guarantee, so
does optional<T>'s assignment operator. It has the disadvantage of making
optional depend on both assignment operator and copy constructor to copy,
but very few classes have a copy constructor but don't have an assignment
operator.

Joe Gottman

 


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk