Boost logo

Boost :

From: Itay Maman (itay_maman_at_[hidden])
Date: 2002-08-07 02:58:30


"David Abrahams" <dave_at_[hidden]> wrote in message
news:06fd01c23dd8$63911d00$62f0fc0c_at_boostconsulting.com...
> From: "Eric Friedman" <ebf_at_[hidden]>
>
>
> >
> > Additional features of my boost::aligned_storage include:
> >
> > * aligned_storage::swap_as<T> and aligned_storage::assign_as<T> provide
> > strong exception-safety guarantee
>
> If those things are supposed to have the "obvious" semantics, well, I'll
> believe it when I see it.
>
> If you don't know something extra about T it isn't in general possible to
> produce a strong guarantee swap or assignment.
>
> -Dave
>

Although swap() cannot uphold the no-throw guarantee, it can be made
(strongly) exception safe. Here is a snip from one of the previous versions
of the variant library, without the alignment handling stuff. (Brad King
should be credited for a bug fix).

template<int MaxSize>
class stack_storage
{

private:
     typedef char[MaxSize] t_buffer;
     t_buffer buf_;

     // Two function pointers
     void (*destroy_func_)(void *p);
     void (*clone_func_)(void *p);

     void clone(void* buf); // Creates a copy of the held value in specified
buffer (via clone_func_)
     void destroy(); // Invokes the destructor (via destroy_func_)

     void* get_ptr(); // Returns a pointer to the internal buffer

public:

      template<typename T>
      stack_holder(const T& t); // clone t to buf_ + assign destroy_func_,
clonse_func_

      void swap(stack_storage& other)
      {
         // Very awkward, but safe

         using std::memcpy;

         // Create two copies of the existing values
         t_buffer copy_me;
         memcpy(copy_me, get_ptr(), max_size);

         t_buffer copy_other;
         memcpy(copy_other, other.get_ptr(), max_size);

         t_buffer copy_me_new;
         t_buffer copy_other_new;

         try
         {
            // Clone other into *this
            other.clone(get_ptr());
         }
         catch(...)
         {
            // Undo it
            memcpy(get_ptr(), copy_me, max_size);
            throw;
         }

         // Create a copy of *this new value + restore old value
         memcpy(copy_me_new, get_ptr(), max_size);
         memcpy(get_ptr(), copy_me, max_size);

         try
         {
            // clone *this into other
            clone(other.get_ptr());
         }
         catch(...)
         {
            // Restore *this new value + Undo first clone + restore old
value
            memcpy(get_ptr(), copy_me_new, max_size);
            destroy();
            memcpy(get_ptr(), copy_me, max_size);

            // Undo the second clone (c'tor has failed so a memcpy will do)
            memcpy(other.get_ptr(), copy_other, max_size);
            throw;
         }

         // create a copy of other's new value
         memcpy(copy_other_new, other.get_ptr(), max_size);

         // From now on only non-throwing primitives are used
         // As always, destructors are assumed not to throw

         // Restore old value of *this + destroy it + switch in its new
value
         memcpy(get_ptr(), copy_me, max_size);
         destroy();
         memcpy(get_ptr(), copy_me_new, max_size);

         // Restore old value of other and destroy it
         memcpy(other.get_ptr(), copy_other, max_size);
         other.destroy();

         // Switch in other's new value
         memcpy(other.get_ptr(), copy_other_new, max_size);

        //Handle other data members
       ..
       ..

      }

};


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