Boost logo

Boost :

Subject: Re: [boost] Boost and exceptions
From: Robert Ramey (ramey_at_[hidden])
Date: 2012-06-25 02:33:19


Emil Dotchevski wrote:
> On Sat, Jun 23, 2012 at 4:19 PM, Robert Ramey <ramey_at_[hidden]> wrote:
> If you can think of a way to provide this functionality less
> intrusively,
> I'm all ears.

I've attached as 100 line test program which I believe demonstrates how
functionality like boost::exception can be implemented.

a) It won't build with my VS 2008 system. It seems that this version
doesn't implement exception_ptr and it's related functions.

b) I compiled and linked with gcc 4.5.3 on my CYGWIN system. Here is the resulting output

$ ./test_misc
caught other exception
caught exception_wrapper_base
caught my_exception
999

This is the output that I expect.

c) The function of the program is as follows

1) The program invokes a chain of calls - the lowest one throws an arbitrary exception - my_exception
2) All exceptions are caught at the next highest level with catch(...)
3) At which an exception_wrapper object is created which contains the original exception along with any data to be attached to the exception. exception_wrapper would more or less correspond to boost::exception.
4) This newly created object is thrown.
5) At the top level, any/all exception_wrapper objects not yet caught are caught and their attached data extracted along with the original exception.

d) Note the following:

1) there is no requirement that any special wrapper be applied at the exception site.
2) It works for ALL exception types. There is no requirement that they be derived from some specific base class.
3) It doesn't require RTTI.

e) I believe this captures the essential functionality of boost::exception while being totally non-intrusive.
Having said that, I didn't look at whole documentation and non of the code of boost::exception so I could easily be missing something.

f) I'm aware that the interface presented here is not the most elegant. The purpose here is to demonstrate that boost::exception can be made non-intrusive and to do so in the simplest way.

g) I did spend some time looking at boost::exception and the C++ standard documentation on the subjects. Also I spent some time experimenting - this was my second try. As has been pointed out on this list, I'm not very knowledgable in this area, so feel free to point out what I'm missing here.

h) This excercise has given me a better understand of the work you've done and the effort you've invested. Of course there's a lot more to it than meets the eye. So please accept my appologies for having given such a hard time.

Just in case the attachement gets separated from this email, I'm including the program source below.

Robert Ramey

// library code
#include <exception>

// MS compatible compiler 2008 doesn't implement these
#if defined(_MSC_VER)

namespace std {
    struct exception_ptr {};
    void rethrow_exception(exception_ptr p);
    exception_ptr current_exception();
}
#else
// gcc
#include <exception_ptr.h>
#endif

// see 18.8.5 Exception propagation

#include <typeinfo>
#include <iostream>

class exception_wrapper_base : public std::exception {
public:
    const std::exception_ptr m_e;
    exception_wrapper_base(const std::exception_ptr & e) :
        m_e(e)
    {
    }
};

template<class T>
class exception_wrapper : public exception_wrapper_base {
public:
    T m_t;
    exception_wrapper(const std::exception_ptr & e, const T & t) :
        exception_wrapper_base(e),
        m_t(t)
    {
    }
};

template<class T>
exception_wrapper<T>
make_exception_wrapper(std::exception_ptr e, T t){
    return exception_wrapper<T>(e, t);
}

// example

// inside of some other library
class my_exception : public std::exception {
};

void test_function1(){
    throw my_exception();
}

// inside a user application

// our one special sauce to all the exceptions and
// then pass them on.
void test_function(){
    try {
        test_function1();
    }
    catch(exception_wrapper_base &ewb){
        // if it's already wrapped
        // ... add sauce
        // just pass it on
        throw ewb;
    }
    catch(...){
        std::cout << "caught other exception" << std::endl;
        // if it's any other exception
        // copy the exception pointer
        std::exception_ptr eptr;
        try {
            std::rethrow_exception(std::current_exception());
        } catch(...) {
            eptr = std::current_exception();
        }
        int t = 999;
        // and create a new exception_wrapper type
        throw make_exception_wrapper(eptr, t);
    }
}

int main(){
    try {
        test_function();
    }
    // to catch some of the exceptions which have been wrapped.
    catch(exception_wrapper_base & e){
        std::cout << "caught exception_wrapper_base" << std::endl;
        try {
            std::rethrow_exception(e.m_e);
        }
        catch(my_exception & me){
            std::cout << "caught my_exception" << std::endl;
            // e has the added on information
            // which me has the original information
            const exception_wrapper<int> & ew = static_cast< exception_wrapper<int> &>(e);
            std::cout << ew.m_t << std::endl;
        }
        catch(...){
            // just skip any all other exceptions not specifically handled.
        }
    }
}




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