Boost logo

Boost :

Subject: Re: [boost] Boost and exceptions
From: John Maddock (boost.regex_at_[hidden])
Date: 2012-06-23 08:04:08


>>> You've looked into this - did you see any "compelling reason" to
>>> inject this code into the serialization or any other library?
>>
>> Let's try and give some examples:
>
> I really didn't want to get is these specifics. But you've sucked me in.

Huh? I thought that's what you were asking for when you asked for
"compelling reasons".

>> 1) Unlike "regular" exception objects, objects which derive from
>> boost::exception can have additional information added to them either
>> at the call site, or later in the call stack. Consider this case:
>> user opens a std::fstream and passes the object to a serialization
>> method which then throws. Currently you may get some information
>> about the failure, but not the file name because serialization
>> doesn't know what that is (as far as I know). However, with
>> Boost.Exception support, the calling code can annotate the already
>> thrown exception, retaining all the information it contains, but
>> adding whatever extra information (file name for example) is
>> available. See
>> http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_transporting_data.html.
>
> Why does the serialization library have to include code from boost
> exception in order to do this?
>
> You can use boost exception at the same place, catch
> the standard exception that the serialization throws, construct you're
> own boost exception and continue on.

No!!!!

Misses the whole point - Boost.Exception allow you to annotate an existing
exception without loosing the original information - and that includes the
*type* of the original exception.

>> 2) As others have already mentioned, Boost.Exception allows arbitrary
>> exception objects to be cloned, amongst other things, this allows
>> exceptions to propagate across threads. For example if a
>> serialization routine is run as a future (quite a reasonable goal),
>> then it would allow exceptions thrown during serialization in the
>> worker thread, to be re-thrown in the calling thread when the result
>> of the future is acquired. See
>> http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_exception_ptr.html.
>
> again the same question.

Consider writing a future - in order to preserve all the exception
information, you would have to be able to catch, clone, and then rethrow
*every possible exception type* that may be thrown by the code that the
future calls. It is quite simply impossible.

However, if all thrown exceptions inherit from boost::exception, then you
simply catch that exception type, ask it to clone itself, and rethrow in a
different thread. You preserve all the original error information, and
crucially, all the original type information, even though the future doesn't
itself know what the actual dynamic type of the caught and rethrown
exception is.

This actually looks compelling enough to me, that we should probably mandate
use of BOOST_THROW_EXCEPTION.

>> For me, I've only used (3), but when you need it it's very useful. Both
>> (1) and (2) look like killer use cases to me - not for you - for
>> your users.
>
> Let me be clear. I don't have any complaint about boost exception per se.
>
> My complaint is the process by which it was inject.

Fair enough, but you're still 4 years too late on that one.

I repeat an earlier question - if Boost.Exception were refactored to put the
"core" exception throwing code either into boost/detail/ or indeed directly
into boost/exception.hpp given that there's not much of it, would that
address at least some of your concerns?

> BUT - now you've sucked me into looking at the merits of including it, I
> don't
> see that it would be of any use. here's typical serialization code:
>
> #include <boost/archiive/binary_iarchive.hpp>
> #include <ifstream>
> ...
> f(...){
> ifsteam is("my file")
> binary_iarchive ia(is);
> try {
> my_data d;
> ia >> d;
> }
> catch(boost::archive::exception ae){
> std::cout << ae.what();
> throw(ae) ; // or throw something else
> }
> return;
> }
>
> So if I want to use boost exception I would just write
>
> #include <boost/archiive/binary_iarchive.hpp>
> #include <ifstream>
> #include <boost/exception/???.hpp>
> ...
>
> f(...){
> ifsteam is("my file")
> binary_iarchive ia(is);
> try {
> my_data d;
> ia >> d;
> }
> catch(boost::archive::exception ae){
> std::cout << ae.what();
> // I don't know how to use boost::exception insert your own code
> here
> boost::exception::throw(?)
> }
> return;
> }
>
> I don't see injecting boost::exception into the serialization code changes
> this in
> any way

Please see my answers above.

Now consider that the serialization code includes some use of
Boost.Filesystem, Boost.Regex (filename parsing) and heaven known whatever
other dependencies the object being [de]serialized depends on (presumably an
object being deserialised could throw any exception Boost is capable of).
If all those exception objects uniformly derive from boost::exception
somewhere in their object hierarchy, then you catch *one* exception type,
annotate it, and rethrow. All the original type information is retained,
clients can catch the boost::exception and enumerate all the information it
holds, or they can catch something more specific like
boost::archive::exception and work from there.

I admit to being new to what boost::exception has to offer, but that looks
pretty compelling to me,

Cheers, John.


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