Boost logo

Boost :

Subject: Re: [boost] [variant2] Need rationale for never-empty guarantee
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2019-03-03 21:36:03


niedz., 3 mar 2019 o 22:10 Andrzej Krzemienski <akrzemi1_at_[hidden]>
napisał(a):

>
>
> sob., 2 mar 2019 o 23:32 Niall Douglas via Boost <boost_at_[hidden]>
> napisał(a):
>
>> >> You see, I would consider any union-based storage as in the same
>> >> category. By definition union-based storage must contain a "pointer" to
>> >> the correct way to interpret that union-based storage.
>> >
>> > I don't understand this. Andrzej says pointers and
>> > means it literally: T*. You say "pointers" and
>> > I have no idea what you mean by it and what relation
>> > it has to exception safety.
>>
>> If an object *selects* another object, then in my opinion it needs to
>> propagate the strongest possible exception guarantees it can for
>> assignment, swap and emplace.
>>
>> If an object *aggregates* other objects, then in my opinion it is
>> permitted to have partial operations. So swap can get half way into
>> swapping the individual members in the aggregate, and bail out.
>>
>> This might help:
>>
>> T*: Selects a T[1...N]
>> unique_ptr<T[x]>: Selects a T[x]
>> vector<T>: Selects a T[0...N]
>> optional<T>: Selects a T[0], or a T[1]
>> variant<A, B, C>: Selects one of a A[1], B[1], or C[1], with all others
>> [0]
>>
>> ---
>>
>> struct: Aggregate of heterogeneous types
>> T[x]: Aggregate of x homogeneous T's
>> array<T, x>: Aggregate of x homogeneous T's
>>
>>
>> Can you see the difference yet? The first group selects an aggregate
>> *elsewhere*. The second grouo IS an aggregate.
>>
>
> Sorry, I cannot see how you are making this distinction. I can see a
> different distinction though:
>
> T*
> unique_ptr<T[x]>
> vector<T>
>
> The above types use indirection through a pointer, so providing strong
> assignment is cheap and quite trivial, and this is why it is provided:
> because it is cheap to implement: no other reason.
>
> aggregates -- no indirection, members stored directly inside the
> aggregate; implementing strong assignment is expensive (double buffering),
> therefore we only get basic.
>
> optional and variant also do not use indirection: they store their values
> in their storage, therefore providing strong assignment can be difficult.
>
> So the driver for deciding on strong versus basic guarantee is not how we
> want to think about these types but a practical factor: how easy it is to
> implement. In case of optional<T> strong assignment is implementable "by
> luck": because it has the "monostate" as part of the contract. But even
> optional<T> has its problems: its swap() is potentially throwing if T
> potentially throws from move constructor or assignment, even if T's swap()
> is noexcept.
>

Correction: optional<T>::swap() 's noexcept depends on T's swap()'s and
move constructor's noexcept. It does not depend on T's move assignment's
noexcept.

>
> Regards,
> Andrzej
>
>
>
>


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