|
Boost : |
From: Emil Dotchevski (emil_at_[hidden])
Date: 2007-10-23 15:00:14
On 10/23/07, Alexander Nasonov <alnsn_at_[hidden]> wrote:
> Your exception class is not a replacement for std::exception. You recommend
> deriving from your class _and_ std::exception.
> <snip>
> It has no is-a relation with std::exception. So, it's more like
> "addition" rather than "extension".
In principle, there is no problem for boost::exception to derive from
std::exception, or even to replace std::exception.
In practice, we have legacy code that derives from std::exception
already, and making boost::exception not derive from std::exception
enables integration with existing 3rd party and standard code through
enable_error_info.
Do you see any practical problems with this design decision?
> > 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.
You probably don't want to replace std::bad_argument with some
boost::bad_argument because you would break standard-complying code
that expects to catch std::bad_argument.
That said, boost::exception does provide integration with the standard
exception classes.
In your own code you can change a "throw std::bad_argument()" to
"throw boost::enable_error_info(std::bad_argument())", which will not
break any existing code that catches std::bad_argument, yet will
enable newer, Boost Exception-aware code to intercept the exception
and add information.
If the std::bad_argument exception originated from the standard
library or some 3rd-party code, then you can catch and throw, like
this:
catch(std::bad_argument const& ex)
{
throw boost::enable_error_info(ex);
}
More information is available here:
http://www.revergestudios.com/boost-exception/boost-exception.htm#existing_hierarchies
> 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.
Do you have a less abstract, real-life use case for this?
In particular, the reason Boost Exception lacks iteration over the
stored tags is that after more than a year of using it in my own code
base, I never needed to iterate.
In general, the rationale for not supporting iteration is that
iteration presumes catching boost::exception and then probing it for
the stored information in an attempt to try to understand what went
wrong.
A better strategy is to catch different types for different failures,
and then (knowing the semantics of each exception type) get the
information you know is available in the exception object.
> > 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.
This can be easily implemented on top of the proposed design:
typedef std::pair<char const *,int> catch_point;
typedef std::list<catch_point> catch_points;
struct tag_catch_points: boost::error_info<catch_points> { };
void add_catch_point( boost::exception & e, char const * file, int line )
{
if( !boost::get_error_info<tag_catch_points>(e) )
e << boost::error_info<tag_catch_points>(catch_points());
(*boost::get_error_info<tag_catch_points>(e)).push_back(catch_point(file,line));
}
and then:
catch( my_error& e)
{
add_catch_point(e,__FILE__,__LINE__);
throw;
}
> <snip>
> std::exception designed with this in mind because what() returns
> char const* and has no-throw guarantee. Your library should follow
> this principle.
boost::exception::what() also returns char const * and has to-throw
guarantee. It follows all standard requirements for exception classes.
> I'd like to repeat it. It's very important to avoid throwing exceptions
> implicitly inside a catch clause.
I see no problem for the code inside a catch to throw exceptions.
Emil Dotchevski
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk