On 12/16/16 22:32, Emil Dotchevski wrote:
On Fri, Dec 16, 2016 at 1:20 AM, Andrey Semashev
wrote: the argument wouldn't be whether or not capturing the
stack trace is integrated into boost::throw_exception, but whether or not it is enabled by default. Either way, the boost::exception class (defined in boost/exception/exception.hpp) should provide a hook for that integration in order to avoid coupling between boost::throw_exception and Stacktrace.
The way I see it, boost::exception already provides everything needed, which is the ability to attach arbitrary data to the exception. I don't think adding more special case capability to it is a wise solution in the long term.
This can be said about __FILE__ and __LINE__ which BOOST_THROW_EXCEPTION captures automatically. The reason why it's done is that 1) the cost in terms of time and space is considered negligible and 2) it is potentially critical for debugging.
The reason why it Stacktrace would need special handling rather than go through the usual Boost Exception machinery is also the same as why there is special handling (members in boost::exception): to avoid coupling with the rest of the Boost Exception machinery, which is considerably heavier and bigger than boost/exception/exception.hpp.
The backtrace itself is not a lightweght object, so the overhead of the generic Boost.Exception machinery is probably not significant. And if that overhead is significant then maybe it could be optimized instead. After all, why have it if we don't want to use it. Also, note that the source location is always injected into the exception (well, as long as you use BOOST_THROW_EXCEPTION or a similar macro), while the backtrace is optional.
The run-time hook can be tricky to implement, that is true, but in the
simplest form it should be doable. The implementation details are of course discussable, but below is something more concrete to get things started.
Introduce a process-wide singleton pointer, which is a pointer to the function that will augment the exception about to be thrown:
typedef void (*exception_augmenter)(boost::exception&);
Consider dynamically loaded libraries.
That is a separate can of worms, which can ruin your day even without the global pointer. The global hook doesn't make it worse per se.
Also consider multiple libraries wanting different hooks.
That would be problematic to support - both with run-time and compile-time hooks (the latter is difficult because of ODR violations). I'm not sure this level of flexibility would be useful either.
A process-wide pointer is very difficult to do in the general case, and I suspect it'd drag a lot more dependencies than capturing the stacktrace would.
The most complicated part is Windows-specific implementation, and it only requires a few functions from WinAPI. Marking the pointer visible on POSIX is trivial.
Consider that boost::throw_exception must support very very old compilers.
How old? I mean, it only has to support the oldest compiler Boost libraries support.
Besides, throwing exceptions and capturing stack trace are thread-local operations, while global pointer would require synchronization with the initialization code.
That's a valid concern, but I think it can be mitigated by caching the pointer. We could also accept the limitation that the augmentor has to be installed once at the beginning of the program and simply not support its multithreaded modification.
Are you proposing to include
in boost/throw_exception.hpp? That's a no-go.
No. Use approach similar to Boost.WinAPI on Windows (i.e. re-declare WinAPI components).
Making it not header-only module? Also a no-go.
No.