|
Boost : |
Subject: Re: [boost] [variant2] Need rationale for never-empty guarantee
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2019-03-03 21:10:46
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.
Regards,
Andrzej
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk