
"Emil Dotchevski" wrote: "Pavel Vozenilek" wrote:
1. exception/exception.hpp (btw, this file name can easily confuse one with the same filename one level down) - assert() may be replaced with BOOST_ASSERT or even better commented out. People may use their own assert implementation and this would make the exception module (something what should be really the core part) dependent on something else.
If there is a requirement for boost libraries to use BOOST_ASSERT, I'll make that change if the library is officially accepted in Boost.
No, there's no such requirement for BOOST_ASSERT and the macro is not universally used. I asked this because I use my own (feature rich) assert and this implementation intentionally clashes with the default assert and due to the structure of a project the best solution for me was to remove the asserts from boost::exception (under assumption there's no chance of them ever being triggered).
2. shared_ptr<> may be replaced by intrusive_ptr<> or home made equivalent. This (a) reduces dependency on other Boost part (shared_ptr does depend on quite few other libs) and (b) the atomic locking used by shared_ptr would be eliminated. This would help a little bit on multiprocessor systems - lock may be hundredths of cycles and during the time access to the memory bus is disabled.
(a) is a valid concern, OTOH shared_ptr is such a low level component of Boost that -- as careful as I am in avoiding physical coupling -- I don't consider it a real dependency; rather, it's a tool for avoiding dependencies.
(b) can be addressed if someone reports having performance issues with Boost Exception. This is highly unlikely since we're comparing the time it takes to copy a single shared_ptr once (at the time of the initial throw) vs. the time it takes for the implementation to unroll the stack until a suitable catch is found.
Ad (a) and Peter Dimov's reply: few years ago when I bcopy'ed shared_ptr it depended on a lot of other code. This may be mistaken or obsoleted. Ad (b): my personal opinion is that for such general purpose library people would feel safer if it is reasonably optimized even for slow paths. Other (over-)optimizations that may be considered: * some to-string conversions could be handled w/o stringstream * if it is applicable (I didn't measured) code bloat caused by inlining on slow paths may be reduced for MSVC compiled by using __declspec(noinline). Strange combination __declspec(noinline) inline void foo() {} is also possible with desirable effects (http://blogs.msdn.com/freik/archive/2005/10/26/485276.aspx)
1. As mentioned above, the ability to iterate through values and/or pass a visitor.
Iteration presumes that you catch a boost::exception knowing nothing about the semantics of the actual exception type that was thrown, yet you want to make use of the data it contains.
One use case would be to log all data contained in an (unknown) exception, for debugging purposes; this is supported by boost::exception::what().
Another use case is when you want to catch exception type A and throw exception type B instead, such that the B object contains all the data from the A object plus some additional information. However, one of the motivations for Boost Exception is that it helps avoid the need to translate exception types, since you can catch A as boost::exception &, add whatever relevant data you have, and then re-throw the original A object.
Use case for iterator over values: I may want an automated checker that verifies that exception A contains only somewhere specified values and nothing else.
4. I would like the ability to collect traces generated by what() function in DEBUG mode, something as:
catch (my_low_level_exception& e) { my_high_level_exception e2; ... fill in e2 e2.add_debug_trace(e); // adds e.what() somewhere, no-op in release mode throw e2; }
Would this work for you:
struct tag_debug_trace: boost::error_info<std::string> { };
void add_debug_trace( boost::exception & e2, boost::exception & e ) { #ifdef _DEBUG if( !boost::get_error_info<tag_debug_trace>(e2) ) e2 << boost::error_info<tag_debug_trace>(""); (*boost::get_error_info<tag_debug_trace>(e2)) += e.what(); #endif }
and then:
catch (my_low_level_exception& e) { my_high_level_exception e2; ... fill in e2 add_debug_trace(e2,e); throw e2; }
Yeah, something like that with visual separation between different exception objects and as a standard part of the library. --------------------------------- About an other poster wish for standardized stack trace: I wrote at least two stack trace libraries requiring manually added macro like void foo() { STACK_TRACE; .... } It would be handy to get something like that semi-standardized next to the boost::exception and able to cooperate automatically with this library. My implementation got quite complicated: thread safe, able to provide one stack trace for catch (exc1&) { throw exc2; } to store stack traces for sucessfully processed exceptions, it was able to collect ad-hoc information like boost::exception can, etc. /Pavel