|
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