2017-05-28 2:10 GMT+02:00 Peter Dimov via Boost
Andrzej Krzemienski wrote:
My first reaction to this is: such a code is again fishy, ...
That may be so, but it changes not the fact that there is the basic guarantee, the standard library offers it because Dave, and then there's the destroy-only guarantee, which the standard library does not use.
Ok, I will agree to this statement provided that you agree that "only destroy or reset" is equivalent to basic guarantee when the invariant is super-wide. I think we are agreeing here. I also acknowledge that the STL requires of T's that after move they are in "vaid but unspecified state".
You are not the only person who feels that destroy-only is better, but this doesn't really matter here.
If the subject of the argument is the formal definition of basic guarantee, then agreed, my preference is irrelevant. But what interests me most what is the optimum guarantee for `expected` and `outcome` in the context ot this library review. And in this case my opinion is relevant to Niall or Vicente, even if it is incorrect.
(It's the same for move, by the way. There are people who prefer destroy-only for moved-from objects. The standard library does not agree with them, this time because Howard.)
Acknowledged. But what do the STL containers/algorithms do with the moved-from objects other than to destroy them or reset them?
I realize that I'm a bit curt, so here's some explanation.
Under the destroy-only guarantee, all your member functions have a precondition on valid(), assuming that you even have such an accessor (of you don't, it's even worse). Most of the time, this doesn't matter, because, as you assume, you'll never encounter invalid objects. Except when you do.
I understand this. But exactly the same observation is to be made for all move-only RAII classes that wrap resource handling. Once you have moves, you get the moved-from state, and hence every member function has a weak invariant: you have to check if it represents not-a-resource. Take std::fstream for instance. And we are using these types and recommend using them. And people do not put defensive if-s anywhere. Some do, but this also isn't a good solution.
So you have to split your code into two categories: functions that will never be called on invalid objects, and functions that can. You then need to make sure that first category functions are never, directly or indirectly, called during stack unwinding, either from a catch block, or from a destructor.
Yes, as with movable objects.
This is possible in principle, even though it's not very reliable, because "never happen" objects, well, never happen, and therefore you often aren't testing the scenarios in which they happen. So when they do happen, it's in production.
But in the context of concern you are describing, valueless_by_exception is no different than the moved-from state. moved-from state is "safe" on `std::vector` but not on `std::fstream`. We are facing this problem in amny many places.
Under the basic guarantee, when your member functions don't have a "valid" precondition because objects are always valid, and when functions taking objects don't need to be split into two categories, some that can only take valid objects, and others that can take invalid ones, the world is simply a better place.
With move semantic world is not this good place any more. You have moved-from states potentially everywhere. And this is smething we are used to. Regards, &rzej;