Boost logo

Boost :

Subject: Re: [boost] expected/result/etc
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2016-02-11 18:32:00


On 12/02/2016 11:57, Emil Dotchevski wrote:
> It appears that you think that C++ exceptions are "unusual" in the same way
> OS exceptions are unusual: the OS detected something bad going on and
> raises an exception, as many OSes do for example in the case of
> dereferencing a null pointer. That's not at all what C++ exceptions are.
> They are in fact specifically designed to replace the need to return error
> codes, so that handling errors is simpler, safer and more testable.

Perhaps I'm biased by mostly developing on Windows+MSVC, but since that
implements C++ exceptions by raising OS exceptions, and OS exceptions
can be caught and processed just like C++ exceptions, I don't see any
distinction between the two. (Though I'm aware that the OS exception
handling mechanism is much more broken on non-Windows.)

And yes, I think that exceptions should be reserved for unexpected
cases. If a method has a case where it is expected to sometimes not
produce a value, then it should use optional<T> or similar.

> As for shared_ptr::operator*, I know it could be made to throw, but that
> would be incorrect design. I mentioned shared_ptr to make the point that
> you're wrong that this kind of design decision can not be made in generic
> C++ code. STL too is full of generic functions that throw to indicate a
> failure, and others that do not, without giving the user a choice. Even at
> the language level, consider that in C++ constructors don't give you the
> option to return an error code, the only way for them to fail is by
> throwing. Why? Because that is the correct design.

The only reason that shared_ptr::operator* does not throw is that the
class author decided that this is likely a hot path and the calling code
has *probably* already checked for null, so it is more *efficient* to
omit the check entirely (and cause undefined behavior if called in
violation of that assumption). As such an assert is used to *hopefully*
catch those violations, but there are only limited cases in which it
will do so. Checking and throwing will always be more *safe/correct*,
but for this particular method the author chose to prioritise efficiency
over safety.

(Although shared_ptr has an additional bias -- if the operator*
precondition is violated then even if the assert is omitted it's almost
certainly going to immediately cause an OS fault anyway due to a null
(or nearly-null) pointer access -- which is arguably equivalent to
always-throw behaviour. Methods on other classes typically won't get
that for free.)

Don't get me wrong, I'm not saying that this is a bad thing. But it can
also get applications into trouble and it is useful to provide both
options. Just look at all the discussion recently about safe numeric
libraries -- that's another case where the language has chosen to value
efficiency over safety, and some applications wish for the reverse.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk