
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