Hi Niall,
Thanks for the response. But I must admit I do not fully understand what
you are saying.
pt., 1 mar 2019 o 11:14 Niall Douglas via Boost
The guarantee provided by variant's assignment is not a strong exception safety guarantee: it is possible that my variant has value A, I want to assign value B, and (due to an exception) I end up with value C. If this happens, the only thing I can reasonably do is to either abandon whatever I was doing or reset the variant to the state that I need. So the guarantee that it is not left empty does not seem to be of much use. But the cost to be paid is noticeable.
I would disagree with this assessment of the strong never empty guarantee provided by variant2.
Do you disagree with the observation that you can get to state C when you wanted to move from state A to state B? Or do you disagree with the statement that variant2 does not provide strong exception safety guarantee? Or do you disagree with my judgement that the never empty guarantee is not of much use?
I have only seen a certain amount of std::variant being used in the wild, written by average C++ developers. In every such case, however, I have never seen any accounting for the possibility of the std::variant being valueless, despite that the codebase does throw exceptions, and that the std::variant is not in temporary storage duration.
Would it be possible for you to give a short invented example that would illustrate what you are saying? or is it something like this: ``` std::variant global_variant; void f() { try { global_variant = B{}; } catch(...) {} // ... // now do a visitation on variant } ``` I agree that this is how you could observe the valueless state. But I also claim that such code (I wait to be convinced otherwise) has already more serious problems than observing the valueless state on variant. You typically do not want your objects to outlive the stack unwinding. And if you do, for globals, you want to provide a transactional-like guarantee. Leaving such objects in "valid but unspecified states" is a design bug. Or am I wrong?
I find that to be a code smell.
I find it a code smell when you leave global objects in a "valid but unspecified state; whether they are variants or anything else. In the code I have written myself where
I used std::variant, I know it will be later modified by programmers who may not account for valueless.
If you used variant (which does not provide a transactional exception safety guarantee) in situations where an exception is thrown when modifying the variant's alternative and the variant outlived the stack unwinding and you were still trying to read it and you considered this a good design, then I would like to be shown such example. I therefore have always wrapped my use of
std::variant with valueless handling code, even if it isn't needed right now, in order account for the future possibility that someone might add a type which can throw during move or copy. It also reminds later programmers about valueless, so it is self documenting.
My position (until I see examples that will convince me otherwise) is that if a programmer observes the valueless state in a variant, then the programmer is doing something wrong with handling exceptions.
This, in my opinion, is exactly the situation which so many people objected to WG21 regarding the possibility of valueless at all in std::variant. It introduces a corner case which few will consider, and it is certainly virtually untestable, so anyone sensible is going to wrap every std::variant with a wrapper to handle valueless.
I find that situation daft. And it was completely avoidable.
For me, a HUGE tick in favour of variant2 is that it has the design which std::variant should have had from the beginning, at little build time nor runtime cost over std::variant.
I will therefore be strongly recommending the use of variant2 instead of std::variant wherever possible. Until WG21 clean up that mess, which I hope variant2 will help persuade them to do.
You are contrasting boost::variant2 with std::variant, but the design space I see is more than just either of them. If std::variant is wrong (which I tend to agree with) it does not immediately imply that boost::variant2is right. Another alternative that Peter indirectly suggested is that it is UB if you try to observe the valuelsess state in std::variant. In this case some usages after a throw are banned, but the model still guarantees the never emptiness. Regards, Andrzej