mr-edd.co.uk :: horsing around with the C++ programming language

fungo

fungo is a C++ library that is designed for those of us stuck using older C++ implementations that do not yet support std::exception_ptr.

In other words, fungo allows you to make a fair attempt at storing and later re-throwing exceptions caught by a catch(...) block. This is useful for propagating exceptions across thread-joins or over C/C++ boundary interfaces.

Recent activity

Code

Clone the repository using mercurial:

> hg clone http://bitbucket.org/edd/fungo

Or get a zip file of the code.

Quick start

#include <fungo/fungo.hpp>

// First we tell a catcher about the exceptions we're interested in.
fungo::catcher mitten;
mitten.learn<std::runtime_error>();
mitten.learn<std::logic_error>();
// ...


// Now we can use fungo to catch and store them
fungo::exception_cage cage;

try { throw std::logic_error("2+2=5"); }
catch (...) { mitten.store_current_exception(cage); }

// cage now stores our exception. 
cage.rethrow(); // throws a logic_error (wasn't sliced in to a runtime_error)

fungo does everything it can to ensure that exceptions aren't sliced when they're caught and copied in to an exception_cage. It does this by sorting registered exception-handlers by the size of their associated exception types (biggest to smallest) and seeing which, if any, of the existing handlers can catch an instance of the exception being registered.

By doing this, fungo is able to attempt to catch the most-derived exceptions first thereby keeping the slicing to a minimum.

If you have a hierarchy of exceptions classes that can be copied and (re)thrown polymorphically, you only need to tell fungo about the root class in that hierarchy and specialize fungo::clone_policy:

struct base_exception
{
        virtual ~base_exception();
        virtual base_exception *clone() const = 0;
        virtual void throw_copy() const = 0;
};

struct derived_exception : base_exception
{
        virtual base_exception *clone() const { return new derived_exception(*this); }
        virtual base_exception *throw_copy() const { throw derived_exception(*this); }
};

namespace fungo
{
    template<>
    struct clone_policy<base_exception>
    {
        static base_exception *clone(const base_exception &e) { return e.clone(); }
        static void rethrow(const base_exception &e) { e.throw_copy(); }
    };
}

// ...

fungo::catcher mitten;
fungo::exception_cage cage;
mitten.learn<base_exception>();

try { throw derived_exception(); }
catch (...) { mitten.store_current_exception(cage); }

cage.rethrow(); // throws a derived_exception

One other useful feature of fungo is the raise() function. When used instead of the regular C++ throw statement, it ensures that any type of exception can be caught with any fungo::catcher:

fungo::catcher mitten;
fungo::exception_cage cage;

try { fungo::raise( misaligned_cryonic_nerve() ); }
catch (...) { mitten.store_current_exception(cage); } // no problem

Further reading

Comments

(optional)
(optional)
(required, hint)

Links can be added like [this one -> http://www.mr-edd.co.uk], to my homepage.
Phrases and blocks of code can be enclosed in {{{triple braces}}}.
Any HTML markup will be escaped.