
On 10/23/07, Alexander Nasonov <alnsn@yandex.ru> 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_h...
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