Home > Frameworks > boost::exception

boost::exception

In C++ there’s a no-throw restriction when it comes to data attached to exception objects.  Circumventing it could be tricky, and this is where the boost::exception shine by, not only allowing any arbitrary data to be moved up to the catch site, but also allow for data copying between threads.

Also, a classic problem with traditional exception handling is that, often, the proper data to describe an error is not available at the throwing level.  The two usual ways to handle this problem is either:

  1. Passing extra data to lower functions so they can throw with the necessary information.  The problem here is code cluttering, and moving a problem down the call stack.
  2. Adding extra exception wrappings up the call stack, but this solution opens all sort of potential side effect issues.

The boost::exception offers a way to add data to the exception object as it moves up the call stack.  There’s a pretty simply situation shown in the boost documentation to explain the problem.  Let say you have a function getting a FILE* as argument.  That function could throw an exception, but at this level the file name is not known.  Boost exceptions let you throw the errno and other source file & line of code to the upper level, where then the filename can be added to the exception data.

For instance, the function receiving the FILE* argument:

#include <boost/exception/all.hpp>
#include <boost/shared_ptr.hpp>
#include <stdio.h>
#include <errno.h>

struct file_read_error: virtual boost::exception { };

void file_read( FILE * f, void * buffer, size_t size )
{
    if( size != fread(buffer,1,size,f) )
        throw file_read_error() << boost::errinfo_errno(errno);
}

And then, from the site calling this function which is the one knowing about the file name:

#include <boost/exception/all.hpp>
#include <boost/shared_ptr.hpp>
#include <stdio.h>
#include <string>

boost::shared_ptr<FILE> file_open( char const * file_name, char const * mode );
void file_read( FILE * f, void * buffer, size_t size );

void parse_file( char const * file_name )
{
    boost::shared_ptr<FILE> f = file_open(file_name,"rb");
    assert(f);
    try
    {
        char buf[1024];
        file_read( f.get(), buf, sizeof(buf) );
    }
    catch( boost::exception & e )
    {
        e << boost::errinfo_file_name(file_name);
        throw;
    }
}

As you can see, each levels of the call stack can add its own piece of information up the chain, until something can handle the exception and gather/handle all the information.

The other bonus of using boost exception is the thread safety capability.  It allows for an exception to carry over between threads without issues.

For instance this function that throw an clone-ready exception:

void do_work()
{
    boost::exception_ptr error;
    boost::thread t( boost::bind(worker_thread,boost::ref(error)) );
    t.join();
    if( error )
        boost::rethrow_exception(error);
}

Could be intercepted and cloned to be carried by an other thread safely, for instance:

#include <boost/exception_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>

void do_work(); //throws cloning-enabled boost::exceptions

void worker_thread( boost::exception_ptr & error )
{
    try
    {
        do_work();
        error = boost::exception_ptr();
    }
    catch(...)
    {
        error = boost::current_exception();
    }
}

 

Advertisements
Categories: Frameworks
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: