|
Boost : |
Subject: Re: [boost] [err] RFC
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2015-11-18 00:49:30
On 17/11/2015 21:06, Domagoj Saric wrote:
>>> Also, if the fallible_result rvalue is left uninspected and contains an
>>> error its destructor will throw (which AFAICT should be safe considering
>>> it is an rvalue and no other exception can possibly be active at the
>>> same time)
>>
>> Throwing from a destructor can cause abrupt termination (or undefined
>> behaviour in some compilers); there are no conditions in which it should
>> be considered "safe".
>
> That's not mandated by the standard...that would be a broken
> compiler/standard library...
It's mandated by the standard if another exception is already in flight.
>> Additionally I'm not convinced that no exception can be active at the
>> same time. Consider function call parameters -- you could easily have
>> one of these get constructed but not consumed yet, and then another
>> parameter throws an exception, resulting in destruction of your object
>> during the throw of an exception.
>
> That can't happen: fallible_results are not meant for passing
> parameters, and thanks to the rvalue semantics this is enforced by the
> compiler rather than just by convention - even if you go to some lengths
> to declare a function as taking a fallible_result (i.e. completely
> contrary to what the type is for)
> foo( fallible_result<bar_t> bar ); (instead of foo( bar ); )
> you'll soon discover that you are doing something wrong because the
> compiler won't let you do anything with that bar...
> (and if the standard would let me declare a special && destructor for
> rvalues there'd be no end to happiness, i.e. you'd get an error
> immediately, at the declaration, and even better codegen in somecases...)
Declaring a parameter as fallible_result<T>&& will satisfy the compiler,
and this doesn't seem unreasonable if it's being passed to a helper
method intended to process such results.
Imagine a function that calculates several results, some of which may
fail, and then calls a combiner method to choose the "best" non-failing
result of the set. Wouldn't the combiner naturally expect a
fallible_result<T>&& as its inputs, since it wants to consume them?
I suppose you could force it to accept result_or_error<T> instead, but
since this isn't the return type of the function it inhibits using
generic type-deducing template code with simplified expressions like:
return combiner(calcA(), calcB(), calcC());
The more problematic case is if the combiner was not expecting failure,
and so someone used the same expression with a combiner that accepted T.
So the compiler calls all three calc methods (constructing
fallible_result<T>s along the way), then gets around to converting the
first one back to T, which throws. This is ok, but then the other two
are destroyed; and if at least one of these throws too, then you're dead.
Sure, you can tell people to only use this as a standalone expression
and not as a function parameter, but this seems very fragile. People
like to inline things, especially rvalues.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk