Boost logo

Boost :

From: Alexander Nasonov (alnsn_at_[hidden])
Date: 2007-10-23 13:24:50


Emil Dotchevski <emil <at> revergestudios.com> writes:

>
> On 10/22/07, Alexander Nasonov <alnsn <at> yandex.ru> wrote:
> > - it recommends deriving all boost exception classes from boost::exception
> I'm confused; this is exactly what Boost Exception recommends.

Your exception class is not a replacement for std::exception. You recommend
deriving from your class _and_ std::exception.

> > - wrapping standard exceptions with correspondent boost exceptions in
> > boost::throw_exception.
>
> boost::exception is designed as an extension of std::exception.

It has no is-a relation with std::exception. So, it's more like
"addition" rather than "extension".

> You don't wrap standard exceptions with correspondent std::exception, you
> just derive std::exception. What do you mean by "wrapping"?

That's what I mean:

catch(std::bad_argument const& ex)
{
    throw boost::bad_argument(ex);
}
... and so on for every std exception.

> The example included in the documentation demonstrates all aspects of
> using boost::exception:
>
> - how to store information in an exception object at the time of the throw,
> - how to append information to an existing exception object at some
> intermediate level,
> - how to access the information at the point of the catch, to format a
> user-friendly message.
>
> This example seems complete to me, but it is hard for me to imagine
> how it would work on someone without much knowledge of
> boost::exception. I am very interested in ideas on how to make this
> example better.

If you caught an exception at upper layer, it'd be extremely useful to
iterate over all tags at lower layers without maintaining a list of tags.
One strategy here is to create a hierarchy of tags with lower-level tags
derived from upper-level tags and have a method that returns a container
of tags:

vector<ThisLayerTag*> infos = get_derived_error_info<ThisLayerTag>(ex);

or something like that with nicer interface.

> > Other important case
> > is stacking up information as an exception is being processed. Stack trace
> > is a good example.
>
> Stack trace can not be implemented in a platform independent manner;
> we need the collaboration of the Boost community to implement it
> correctly on multiple platforms. It is a debugging feature that once
> implemented, will appear automatically in the ::what() message.

OK, I'll call it "catch points" or "trace points" then. User push_back
something in every catch clause and reshow. Unlike tags, which have
unique types, this stack stores values of one type. For example,

catch( my_error& e)
{
    e.push_back(catch_point(__FILE__, __LINE__));
    throw;
}

where catch_point is std::pair<char const*, int> or a struct.

> Other "stackable" information can be stored in boost::exceptions by
> storing a container object (such as std::vector) using error_info,
> then accessing it by get_error_info to add more elements.

OK. Though, distinction between unique tags and tags associated with
a container should be more clear.

> > Also, it should be clear how library handle bad_alloc. In some situations,
> > it's fine to rethrown bad_alloc instead of original exception but more fine
> > tuned behaviour is require in other situations.
>
> If you run out of memory at just the right time when using Boost
> Exception, you might throw bad_alloc instead of the exception you
> wanted to throw. However, this is not specific to boost::exception;
> for example, you'll get the same behaviour from any exception object
> that contains a std::string.

There is a fundamental difference between throwing bad_alloc when
trying to throw another exception and doing a lot of things inside
a catch clause. In the latter case, it's good not to throw at all.
std::exception designed with this in mind because what() returns
char const* and has no-throw guarantee. Your library should follow
this principle.

> In general, failure to throw an exception can not be "fine tuned". For
> example, with or without Boost Exception, throwing requires memory
> allocation, and when that allocation fails, something else (typically
> not very friendly) happens.

I believe, it can be. For example, storage can be preallocated in
my_error ctor. If push_back inside a catch clause throws, the library
can set a flag.

I'd like to repeat it. It's very important to avoid throwing exceptions
implicitly inside a catch clause.

--
Alexander

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