Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom exception hierarchy. Dreaded diamond from std::exception and std::bad_alloc

I Have a problem with inheritance in my own exception hierarchy.

The class Exception has very good functionality (backtrace, logging, ...), so it is my base class for any exception. It inherits from std::exception as I see suggested in many webpages. Also, I'm using a unit test framework that reports any std::exception being throw unexpectedly. But in a final word, it is just for convenience.

Then, I have a new OutOfMemoryException class which will be throw by a custom new_handler. This class inherits from Exception, but also inherit from std::bad_alloc for compatibility with existent code. This is more important I guess, since new will not throw std::bad_alloc anymore.

The problem here is obvious: since std::bad_alloc derive from std::exception, I have a dreaded diamond situation.

class Exception : public std::exception { };
class OutOfMemoryException : public Exception, public std::bad_alloc { };

Sadly, as you can see here stackoverflow.com... standard exceptions do not virtual inheritance, so std::exception is an ambiguous base class.

Then:

  1. Is it possible to solve this in any way? (I don't know, any class or template trick)

  2. If it is not, is preferable that Exception does not inherit from std::exception or OutOfMemoryException does not from std::bad_alloc

I could hack the unit test framework due its permissive licence.

Thank you in advance and sorry, I am not a very good english speaker.

like image 297
Daniel Avatar asked Mar 06 '14 03:03

Daniel


1 Answers

There is a way to have your extra exception functionality but without having to create another exception hierarchy. I.e. you can throw standard exceptions with your extra bits:

struct MyExceptionInfo { /* your extra functionality goes here */};

template<class T>
struct Ex : T, MyExceptionInfo
{
    template<class A1, class... Args>
    Ex(A1&& a1, Args&&... args)
        : T(std::forward<A1>(a1))
        , MyExceptionInfo(std::forward<Args>(args)...)
    {}
};

int main() {
    try {
        throw Ex<std::runtime_error>("oops");
    }
    catch(std::exception &e) {
        if(MyExceptionInfo* my_info = dynamic_cast<MyExceptionInfo*>(&e)) {
            // use MyExceptionInfo here
        }
    }
}

You may also like taking a look at Boost.Exception library for inspiration.

like image 51
Maxim Egorushkin Avatar answered Sep 21 '22 02:09

Maxim Egorushkin