Boost logo

Boost :

From: Pavel Vozenilek (pavel_vozenilek_at_[hidden])
Date: 2007-10-21 12:40:52


"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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk