Boost logo

Boost :

From: Eric Friedman (ebf_at_[hidden])
Date: 2003-10-27 04:09:56


Jaap Suter wrote:
>>Variant provides the basic guarantee for assignment lhs = rhs by copying
>>the content of lhs onto the heap before its destruction. Then the
>>content of rhs is copied to the storage of lhs. In the event of success,
>>the backup is destroyed; in the event of an exception, the lhs variant
>>stores a pointer to the backup and "redirects" all visitation requests
>>accordingly.
>
>
> I must admit that I have not looked at the implementation, nor at the most
> recent version of the documentation, but this behaviour is new to me. I
> thought the double-storage technique was still used in case there was not at
> least one no-throw copy-constructible bounded-type in the variant (possibly
> being boost::empty).

Double storage has been replaced by the above-described temporary heap
backup strategy so as to incur overhead only when/if variant assignment
occurs (vs. the constant space inefficiency incurred by double storage).

Heap backup will not be used for assignment to a variant if the content
type of the right-hand side is nothrow copyable.

As well, heap backup will never be used for assignment to a
variant<T1,...,TN> if *any* of its bounded types Ti are nothrow
default-constructible. (Note, this is regardless of the content of the
right-hand side.)

> I don't want to bring up the old discussion again, but
> I'm wondering whether the above heap-allocation occurs even if the
> variant consists solely of non-throwing types. This would render it
> unusable for me, as I cannot allow allocations in all situations.

If the types appropriately trigger has_nothrow_copy or
has_nothrow_constructor in a manner such as I've described above, then
heap backup will not be used. (The code with calls to operator new will
never even be compiled.)

>>So from an exception-safety point of view, it really doesn't matter too
>>much whether Jaap's state types have nothrow constructors or not. The
>>only difference will be that variant will avoid heap backup if any of
>>the types are nothrow default-constructible. (Or if all of the types are
>>nothrow copy-constructible, but that doesn't apply in this case.)
>
>
> So can I assume Boost.Variant can detect non-throwability and act
> accordingly (not do an allocation if not necessary)?

Yes, via the type_traits library. Without compiler support, however, you
likely will need to specialize the appropriate type_traits templates for
your user-defined types.

> Brian does bring up another point, which is the order of destruction and
> construction. Is this garantueed, or merely a consequence of the current
> implementation scheme? Is it possible to make the order of dtor and
> (copy-)ctor an explicitly document feature that can be relied upon?

It is not guaranteed. For example, since changing from double-storage to
temporary heap backup, the order has reversed. I'm not sure what the
value of a guaranteed order would be anyhow.

> On a related note, is it garantueed that the order of types in a given
> sequence (for variant) corresponds with the order of the different
> which-indices of the variant? In other words, if I pass in list<float, int,
> bool> is it garantueed that which() returns 0 for float, 1 for int and 2 for
> bool?

Yes, absolutely. I have not yet seen a good reason (e.g., implementation
efficiency) why variant should not make this guarantee.

> Perhaps even better, is it possible to provide a nested template in
> variant that allows me to do the following:
>
> typedef variant<float, int, bool> my_variant;
> int p = my_variant::which_for<float>::value; // p is 0, 1 or 2;
> int q = my_variant::which_for<int>::value; // q is 0, 1 or 2 and not p;
> int r = my_variant::which_for<int>::value; // r is 0, 1 or 2 and not p
> nor q;
> int w = my_variant::which_for<char>::value; // possibly compile error, but
> preferably w is -1 indicating it's not in this variant.

I think this would be better handled with code such as the following:

   int p = mpl::index_of< my_variant::types, float >::value;

Unfortunately, mpl::index_of does not yet exist. Perhaps this is enough
motivation for me to finally create it.

HTH,
Eric


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