
On Tue, Apr 2, 2019 at 7:07 PM Gavin Lambert via Boost < boost@lists.boost.org> wrote:
On 3/04/2019 13:38, Emil Dotchevski wrote:
The problem with explicitly testing is that it must be done everywhere because we don't know if maybe we are being called from an
error-handling
context (note, this doesn't necessarily mean exception handling). For example, every member function must check if the class invariants are in place for *this (assuming UB is not acceptable).
How is this different if the instance can be empty, or can unexpectedly change from type A to type B?
If you don't know whether you're handling an errored instance or not, then it could be unexpectedly empty (with one variant implementation) or it could be unexpectedly type B (with another implementation). I don't see any practical difference between these cases.
Consistent with the basic guarantee, if you assign one std::vector to another and the copy operation fails, the contents of the target vector is not specified, but it is guaranteed to be a valid vector, so that if you happen to handle it later, you can safely do with it what you do with any other vector: you can insert or delete elements, iterate, whatever. By analogy with your position, a better design for std::vector would be to define a special "error" state that you must check for *every* time you handle a vector, and the justification for that design is that otherwise it might be unexpected to see a vector in a half-copied (but valid, by definition) state. Do you see the practical difference now? Going back to variant, in one case, we are defining an empty state, which forces the user to provide explicit handling for that state, *everywhere*. Otherwise, we are not defining an empty state, and the user doesn't have to provide special handling, *anywhere*, because he doesn't have to care that A "unexpectedly" changed into B. He sees a B, he does what he normally does with B.