Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2002-08-09 13:29:58

           David Abrahams * Boost Consulting
dave_at_[hidden] *

----- Original Message -----
From: "Douglas Gregor" <gregod_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Friday, August 09, 2002 2:27 PM
Subject: Re: [boost] Re: Empty boost::variant semantics (was
Re:Re:Mini-reviewrequest: aligned_storage.hpp)

> On Friday 09 August 2002 12:52 pm, David Abrahams wrote:
> > > We decided long ago that #1 is bad, because it makes variants harder
> >
> > use.
> >
> > > But if we choose #2, then the current assign/swap semantics don't
> >
> > the
> >
> > > basic guarantee!
> >
> > I don't understand why that must be the case. Are we still working with
> > assign_as<T>, swap_as<T> et al?
> > If so, it seems to me that these can just dispatch to the operation
> > for T, and assuming T's assignment meets the basic guarantee, all is
> Because we have to handle the case where we are assigning a T to a U. For
> instance:
> void foo(T& t, U& u)
> {
> variant<T, U> v(t);
> v = u;
> }
> Prior to the assignment "v = u", we have memory inside 'v' that stores a
> of type 'T'. After the assignment "v = u", that same memory inside 'v'
> store a value of type 'U'. Because the U needs to occupy the same space
> the T does now, the T must be destructed before the U is constructed.
> However, U's construction can throw so we need to save the value of T.

Why? Isn't "empty" one of the allowed states for the variant object?
If an exception is thrown during U's construction, you're left with an
empty variant. Seems simple enough to me. Besides that, you can't save the
value of T in any useful way without specific help from the T type (e.g. a
persistence mechanism -- and I don't think we want to go there).

> That's
> fine, but how do we _restore_ the saved value of T?

You can't, period the end. A destroyed object stays destroyed.

> For instance, say we do
> this:
> char the_memory[max_sizeof(T, U)];
> variant& operator=(const U& u)
> {
> T* asT = reinterpret_cast<T*>(&the_memory[0]);

I don't understand why the reinterpret_cast here. (T*)(void*) would be

> T savedT(*asT); // save a copy of the T value. it's okay if this throws
> asT->~T(); // destroy the T, won't throw
> try {
> new (&the_memory[0]) U(u); // might throw
> }
> catch(...) {
> // restore the T value
> }
> }
> What goes in that catch block? We can't copy-construct savedT into
> because that might throw and we'd be left with the_memory in an
> state. We can't use T's assignment operator because there's no T there.

Right. That's all in the domain of "heroic attempts to ressuscitate the

> > I don't expect to be able to repair exception-broken types (i.e. those
> > whose operations don't even meet the basic guarantee).
> That's fine. Unfortunately, the problem above occurs even with types
> assignment and copy constructor meet the strong guarantee.

I still don't see the problem.


Boost list run by bdawes at, gregod at, cpdaniel at, john at