On Sat, Apr 6, 2019 at 2:37 AM Rainer Deyke via Boost
On 06.04.19 02:46, Emil Dotchevski via Boost wrote:
I do not think that it is a bug to access an object that is in a valid state. In fact, the reason why the state is defined as valid is so that
you
can safely work with that object, even after a failure was reported.
One thing that bothers me about this view is that it is inconsistent with how the language treats uninitialized variables. Every bit pattern of a variable of type 'char' is a valid value. However, reading from an uninitialized variable of type 'char' is undefined behavior. On a physical level, a variable of type char will always have a valid value, but on the conceptual level, it can also have a special "uninitialized" state from which it is legal to assign a new value but not to read the current value.
I find that using this conceptual uninitialized state actually makes it /easier/ to reason about the correctness of my code. Any code that depends on the value of an uninitialized variable for its behavior is automatically incorrect. Any code that reads an uninitialized variable, even if the value read does not affect the observable behavior of the code, is automatically incorrect. Just declaring an uninitialized variable is a red warning light that I need to be careful to assign a value to that variable before reading from it. So long as I follow these rules, I never have to worry about my code unexpectedly breaking due to an uninitialized variable having an unexpected value.
To me, the "valid but unspecified" state of an object after an exception is thrown from a function with the basic exception guarantee is conceptually very similar to the state of an uninitialized variable. If I catch such an exception while the object is still in scope, that's a red warning light that I need to either assign a new state to the object or allow the object to go out of scope. Anything else risks the same sort of errors as are caused by reading from an uninitialized variable.
To clarify, this discussion is not about initialization. If a variant object fails to initialize, accessing it is UB, just like it is for any other uninitialized object. I get what you're saying, that if an assignment fails, logically you wish to treat the resulting state something like an uninitialized state. The problem is that your program can no longer assume that all objects it works with are valid -- that is, RAII is out the window -- except if the special state is (by definition) a valid state. But this contradicts your wish, because a valid state is nothing like an uninitialized state. It has to be on your mind all the time, because now objects in this state are valid (by definition) and you must define behavior for functions that are handed such objects.