From: Eric Friedman (ebf_at_[hidden])
Date: 2002-08-08 17:11:21
OK, let me summarize variant's behavior as currently implemented in the
On default construction, variant<T1, T2, ... , TN> default constructs
T1. If T1's default construction throws, variant is never constructed,
and so there is no problem.
On copy construction from a non-empty variant, variant copies the given
variant's held value. Again, if the copy throws, variant is never
constructed, and so there is no problem.
The difficulty comes with variant assign. On assign from a non-empty
variant, *this clears itself (i.e. makes itself empty) and then copies
the given variant's held value. If the copy throws, we now have a
problem, as *this is now an empty variant.
The same problem occurs with variant swap, as variant swap is simply an
optimization for the case in which both *this and the given variant are
holding values of the same type (in which case a straightforward swap is
performed). If *this and the given variant are holding values of
different types, then the standard swap algorithm is invoked with *this
and the given variant as arguments. Note that since the standard swap
algorithm is implemented in terms of assignment, the preceding paragraph
applies; that is, variant swap can result in: 1) success; 2) *this
becoming empty; or 3) the given variant becoming empty.
Now to answer your question as to what expressions are well-defined for
an empty variant, var1:
var1.empty(); // returns true
var1.clear(); // essentially a no-op, as var1 is already empty
var1.which(); // returns -1
var1.type(); // returns typeid(void)
// value is an object of type T, where T is convertible to one of the
// types bounded by var1.
var1 = value; // attempts to copy value
// var2 is another variant, which may or may not be empty.
var1 = var2; // attempts to copy var2's held value
var1.swap(var2); // attempts to copy var2's held value; clears var2
// if successful
--- Note that visitation of an empty variant is an undefined operation! How nice it would be if variant could maintain the strong exception-safety guarantee... (Maybe section 3.8 of C++0x won't be so strict...) Now I have some questions of my own: 1) Should variant::clear() become part of variant's public interface? That is, is the empty-variant concept somehow _useful_, or is it just an unfortunate necessary consequence of not having the strong guarantee? 2) Is it OK to leave visitation of an empty variant undefined, or should it be well-defined to throw some particular kind of exception? Sorry for the long message, but empty variant semantics complicate matters quite a bit! Thanks, Eric Friedman -----Original Message----- From: Douglas Gregor [mailto:gregod_at_[hidden]] Sent: Thursday, August 08, 2002 1:19 PM To: boost_at_[hidden] Subject: Re: [boost] Re: Mini-review request: aligned_storage.hpp On Thursday 08 August 2002 05:59 am, Eric Friedman wrote: > Well, having the strong guarantee does make variant's use much, much > nicer. > > Now, in the process of removing the undefined behavior from swap and > assign, I've had to reintroduce the notion of an empty variant > (namely, an empty variant is one that has only "partly" made it > through an assign or a swap). *sniff* I want the strong guarantee back *sniff* Could you give us a summary of the semantics of an empty variant ? I'm thinking of it like a singular iterator, where you basically can't do anything with it other than give it a useful value. Does 'empty' now have a purpose? Doug
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk