|
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