Boost logo

Boost :

From: Hamish Mackenzie (boost_at_[hidden])
Date: 2002-02-05 14:52:26


On Tue, 2002-02-05 at 18:53, Howard Hinnant wrote:
> On Tuesday, February 5, 2002, at 01:36 PM, Hamish Mackenzie wrote:
>
> >> However if the vector uses 1 (move construct) to move the elements out
> >> of the way, and an exception is thrown while copy assigning x into
> >> place, then the vector is still in a valid state. There are no holes
> >> of
> >> uninitialized memory. Basic exception safety has been maintained.
> >
> > But even 1 will leave the source damaged will it not? So an exception
> > could still lead to double destruction of the same object.
>
> Nope. Use of #1 to move elements from the end into the unused capacity
> leaves a vector that is longer than the original with a region of
> elements in a (for example) default state in the middle. With #3 these
> middle elements are destructed. This half way state must either be
> valid, or it must be clean-up-able as one starts to copy the argument x
> in. I much prefer to keep the vector in a valid state at all times.
> This approach produces much cleaner, tighter code than doing a try/catch
> and then putting things back in order in the catch clause.

Ok I see what you mean now. So would this work for option 1?

template< class T >
void move_construct( T *destination, T &source )
{
  using namespace std;
  construct( destination );
  move( *destination, source ); // as per previous post
}

void move_construct( int *destination, int &source )
{
  *destination = source;
}

Also do we need a helper for using this on the stack?

template< class T >
move_to_here
{
  unsigned char buffer_[ sizeof( T ) ];
  T *get() { return reinterperet_cast< T * >( &buffer_ ); }
  const T *get() const { return reinterperet_cast< T * >( &buffer_ ); }

public:
  move_to_here() { construct( get() ); }
  // not sure if it should have default constructor
  
  explicit move_to_here( T &source )
  {
    move_construct( get(), source );
  }
  ~move_to_here() { destroy( get ); }

  operator T &() { return *get(); }
  operator const T &() const { return *get(); }
};

Then you could do this

move_to_here< T > temp( x );

This might even help on compilers that do not do return value
optomization

move_to_here< T > f()
{
  T x;
  return move_to_here< T >( x );
}

Hamish Mackenzie


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