On Sat, May 27, 2017 at 3:15 PM, Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
I suppose either interpretation is correct, depending on how strong you wan the invariant to be.
Nope, this is a matter of definition -- basic exception safety is _defined_ to mean something. Other interpretations are incorrect, or rather, disagree with the definition.
But tell me this. Consider the example with class Man above:
``` struct Man { std::string fist_name, last_name; }; Man m1 = {"April", "Jones"}; Man m2 = {"Theresa", "May"};
try { m2 = m1; // suppose it throws } catch(...) { } ```
Object m2 after recovering from stack unwinding may be in the state {"April", "May"}, which is a "valid state". Would you call it a valid state? It is "valid" in the sense that reading values from its members does not cause UB, but its "high-level invariant" (that m1 should refer to an existing person) is broken. It conveys no useful information.
This is not about usefulness but validity. When we say that vector::push_back has basic exception safety guarantee (in general, it is strong in case no reallocation occurs), it doesn't mean that you're going to find anything "useful" in the vector in case of failure. It only means that any objects that remain in the vector are in valid state, and the vector itself is in a valid state. What does it mean for an object to be in valid state? This means that its invariants are in place. In C++ this is formally supported by the semantics of constructors: a constructor succeeds in establishing the invariants of the type or it does not return. Note that there is no provision to report a failure (to establish the invariants) except by throwing. This is not an omission but a deliberate design choice. Emil