$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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