On Sunday 29 September 2013 15:55:01 Emil Dotchevski wrote:
On Sun, Sep 29, 2013 at 2:23 PM, Evgeny Panasyuk
wrote: 2. Temporary objects: log() << may_throw() << endl; log() returns some temporary object which does some finalizing work in destructor. If that destructor is called due to stack unwinding - then finalizing part will be different.
Here, if may_throw() throws, ~log() must not throw. Therefore it is possible for the user to not be notified about a logging failure. If it is critical for the user to be notified about all logging failures, then then ~log() must not do any logging. How critical this notification is doesn't depend on whether or not may_throw() emits an exception.
In case of Boost.Log, ~log() would actually push the log record to the library for processing (applying final formatting, writing to files/console, etc.). If the streaming statement fails with an exception, ~log() must not do anything and let the exception propagate. OTOH, when the streaming expression completes normally, the record processing may throw itself, which makes ~log() a throwing destructor. So you see, no errors are lost, but in some cases work must be suppressed for correct behavior. Writing throwing destructors is discouraged, everyone knows that. But sometimes you just need it because it offers benefits compared to other approaches. unhandled_exception_count() is crucial to make that possible. There are restrictions for such classes, e.g. they should not be used as members of other classes or allocated on heap. But log() above is never intended to be used that way.