Boost logo

Boost :

Subject: Re: [boost] [Exception] Why is there no non-const version ofget_error_info?
From: Adam Badura (abadura_at_[hidden])
Date: 2009-08-20 02:03:29


> I'm curious, could you post more information about your use case?
> What's this vector, what kind of objects/info does it store? I'm not
> against your request, but I want to understand your motivation better.

    In our system we use Observer pattern through Observable and Listener
classes. Now Observable in its core function "notify" iterates through all
registered Listeners and calls their "onNotify" function. This is quite
simple. However it gets complicated once we start to take exceptions into
account.
    (Generally Listener's onNotify should not throw. This is motivated with
two reasons: 1) it should be simple and fast, 2) object which caused the
notification most likely cannot handle the exception anyway. Or at least
such are popular guidelines for implementing Observer pattern. However in my
opinion this is inconvenient [especially if one wants to be correct
according to Standard and must in result take into account that almost any
standard function may throw almost anything]. It is hard to write and
maintain such "onNotifys" and I'm afraid that it might be in general not
possible at all. So we do take into account exceptions thrown from
"onNotify".)
    Now consider a case where there are 3 Listeners. "notify" executes.
First Listener has its "onNotify" called and does just fine. But second one
throws. There is no way to somehow revert the "onNotify" already executed on
the first Listener. So if we just propagate the exception we will end in
incorrect state since first Listener was already notified, second is in
state dependent on the exception and third was not notified at all.
    My idea was to catch any exceptions thrown from "onNotifys", store them
in the vector and then rethrow a different exception (for now called
MultiException) which would contain that vector as its data.
    This makes it much harder to catch the exception since now to catch
exception X you will have to catch exception X and MultiException to see if
it contains X. On the other hand exceptions from "notify" will not usually
be handled anyway and the exception data serves only diagnostic purposes. So
I do not consider it a major issue.
    My first design was to do code like:

    typedef boost::error_info<
        SubExceptionsInfoTag,
        std::vector< boost::exeption_ptr >
> SubExceptionsInfo;

    // Does not throw.
    MultiException exceptionObject;
    // May throw. We haven't started notifying yet so no problem.
    exceptionObject << SubExceptionsInfo( std::vector< boost::exeption_ptr
>() );
    // Does not throw.
    // THIS IS NOT POSSIBLE BECAUSE CURRENTLY THE RETURNED POINTER IS CONST.
    std::vector< boost::exception_ptr >* pExceptionsVector =
        boost::get_error_info< SubExceptionsInfo >( exceptionObject );
    // Prepare memory for worst case: every Listener throws.
    // May throw. We haven't started notifying yet so no problem.
    pExceptionsVector->reserve( m_listenersList.size() );

    // We are ready with exceptionObject. Start actual notifications.

    for each listener in listenersList
    {
        try
        {
            call onNotify on the listener
        }
        catch ( ... )
        {
            // Store the exception and continue the loop.

            // current_exception does not throw.
            // push_back will not throw since:
            // 1) memory is already reserved,
            // 2) boost::exeption_ptr copy constructor does not throw.
            pExceptionsVector->push_back( boost::current_exception() );
        }
    }

    // If any exception was thrown then throw exceptionObject.
    if ( !pExceptionsVector->empty() )
        // exceptionObject copy constructor does not throw.
        throw exceptionObject;

    With get_error_info returning a const pointer this no longer is
possible. The closes approach would be to just have a simple vector with
pre-reserved memory and then after the loop we will construct MultiException
add that vector to it and throw it. However this may fail twice: adding
vector to the exception and copying the vector. If this fails then a new
exception will be thrown and original exception data will be lost. And I
think it is bad because it can be quite easily written so that it either
fails before notifying or fails only with onNotify exceptions.

    Adam Badura


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