2017-06-02 8:57 GMT+02:00 Gavin Lambert via Boost
On 2/06/2017 18:45, Andrzej Krzemienski wrote:
There is a reasonable mental model behind it. But you have to forget the other example (where Niall is using `result<T>` as though it were a `boost::optional<T>`).
It does make more sense that way around.
I would protest for one. You either throw from destructor of you don't
throw from destructor. But I do not accept that you sometimes throw and you sometimes don't.
The purpose of avoiding the throw when std::uncaught_exception() is true is to avoid confusing everyone with a validation error when you're already in the middle of an unwind (and thus the thing you were validating is probably uninteresting now). This also avoids clobbering the original exception with your new one, which makes life better for everyone.
But there is a more fundamental objection to it. Unless you use destructors
to perform significant tasks and business logic, the normal usage of C++ classes is that other member function do the business logic, and destructors only clean up resources. If you failed to do the business logic you start the stack unwinding because other people up the stack depend on your having finished your part of the logic. In contrast, when you have failed to release resources, people up the stack still consider your business task as finished and they can work with it, and likely will not use the resource you are about to waste (and even if they need it, they will be informed by a throw from a constructor of other resource-handling class).
While I agree in general, there are occasionally some interesting benefits from abusing destructors. One such I've seen in Google Test, where you can add arbitrary data to any assertion just by streaming it, eg:
EXPECT_TRUE(foo(bar)) << "foo did something weird" << bar << baz;
The way this works is to collect up the items into a temporary object which then assembles into a string and carries out the actual action in the destructor, which obviously can throw for several reasons.
Abuse? Yes. But it enables a very nice coding syntax.
I do not mind it. You do not start evaluating your assertion when the stack is being unwound anyway. But I would expect std::terminate if evaluating `bar` throws and then the destructor also throws. I mean both "I accept it" and "I prefer it". Regards, &rzej;