On Thu, Apr 18, 2019 at 2:41 AM Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
x1 = std::move(x2);
This throws, and leaves the objects in an unspecified (albeit "valid") state, an exception handling is stopped prematurely, so that the objects remain in scope and the programmer makes no attempt to put their values into a known state. The only guarantee we have now is that no operation on `x1` or `x2` will cause an UB.
Not true. The only operations you can perform on those objects are either
(a) ones with no preconditions or (b) those where the preconditions are
checked first and found to be valid.
The problem with an illegal-to-observe zombie state is that it adds an
unexpected precondition to copy/move construction, and that precondition is
viral. For instance, having such a precondition breaks the following:
void ByRef(vector<PossiblyZombieObject>& v)
{
v.resize(v.capacity() + 1); // error if v contains any zombie objects
}
or even
void ByValue(vector<PossiblyZombieObject> v) { /* ... */ } // error if v
contains any zombie objects
And even if callees decided that want to protect against this (and let me
reiterate, that should never be a requirement), they cannot, precisely
because the zombie state is illegal-to-observe.
A std::variant in the valueless_by_exception state is copy/move
constructible because that state is observable, and that is by design.
Specifically, valueless_by_exception is not a zombie state, but it is a
weakening of the invariants from "exactly 1 of n types" to "at most 1 of n
types". How much that matters is ultimately what we are debating.
--
Nevin ":-)" Liber