On 3/2/19 2:24 PM, Andrey Semashev wrote:
On 3/2/19 1:44 PM, Andrzej Krzemienski via Boost wrote:
sob., 2 mar 2019 o 10:36 Andrey Semashev via Boost
napisaĆ(a): On 3/2/19 11:56 AM, Andrzej Krzemienski via Boost wrote:
This is where my imagination fails me. I cannot imagine why upon
bad_alloc
I would be stopping the stack unwinding and determining size of my vectors. This is why I ask about others' experience with real-world correct code.
That is not an unimaginable scenario. If you have two branches of code, one requiring more memory but better performance, and the other that is slower (or maybe lacking some other qualities but still acceptable) and less resource consuming, operating on the same vector, you will want the vector to stay valid if memory allocation fails. Although not specifically with vectors, I had cases like this in real world.
Thanks for sharing your experience. I am not sure we are on the same page here. Are you describing an operation where an operation on vector fails to allocate more storage and therefore throws and leaves the *value* of the vector unchanged (i.e., an operation with strong exception safety guarantee)? Or are you describing an operation that reuses memory owned by a vector and discards the vector's value? Boith these cases can be described as "never observing the value after a failed operation with a basic exception safety guarantee". Or are you describing a different situation?
As I mentioned, I usually don't rely on standard containers in situations when I want complete control over memory allocations, so vector is not the component I was talking about. However, the program logic is often closer to the strong guarantee because I would normally try allocating memory early, before the real work is done. Though, in some instances some data is modified in non-harmful way in case of OOM.
There are a few instances when I want to "undo" the failed operation, in which case the code relies on a particular "half-way through" state of the program. The rollback process requires that there is a known number of steps that were completed before failure, and the data associated with those steps is in a valid state. From the failed operation standpoint, this is a "strict" basic guarantee, from the underlying components, like containers, this is almost certainly a strong guarantee.
I call "strict" basic guarantee, as opposed to just basic guarantee, a case, where the program is allowed to have a *subset* of valid states upon failure. Maybe there is a better term for this. I mean, for a hypothetical initially non-empty vector, a basic guarantee push_back() is allowed to leave the vector empty upon failure, but that might not be an acceptable outcome for a higher level user's program. In my case, I require a particular state of the program upon my operation failure. This state may not be the same as before the operation started, but it must at least include results of the steps the failed operation has managed to complete. This allows these steps to be rolled back.
I'll add that I could probably agree with you that observing the result of a failed "purely" basic guarantee operation is not useful. You basically have no guarantees about the state of the program, except that the objects can be destroyed or re-initialized from scratch. However, "strict" basic guarantee is more prevalent in practice, even though it is often not documented so, and observing result of failed such operation can be useful, provided that the restrictions on the operation failure outcome match your requirements.