Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I copy-construct a boost::exception with the error info?

Consider the following code employing boost's exception class:

class exception : virtual public boost::exception {
    // ...
};

template<typename Exc>
class exception_impl : virtual public std::exception
                     , public Exc {
public:
    exception_impl(const Exc& exc) : Exc(exc) {}
    virtual const char* what() const throw() {return "blah";}
};

(In reality this code is more complex. For example, exception_impl only derives from std::exception if the latter isn't already a direct or indirect base class of Exc. But this just distracts from the problem I have, so I have skipped over it.)


Given this, I can now derive my own exception classes:

class some_exception : public exception {
    // ...
};

And use them:

struct tag_test_int;
typedef boost::error_info<tag_test_int,int> test_int_info;

void f()
{
    boost::throw_exception( exception_impl<some_exception>() << test_int_info(42) );
}

However, it turns out that the resulting exception does not have the test_int_info object. So I changed the exception_impl constructor to provide some diagnostic information:

    exception_impl(const Exc& exc)
    : Exc(exc) {
        std::cerr << "========================================================================\nexc:\n";
        std::cerr << boost::diagnostic_information(exc);
        std::cerr << "========================================================================\n*this:\n";
        std::cerr << boost::diagnostic_information(*this);
        std::cerr << "========================================================================\n";
    }

This indeed shows that the information gets lost when I copy the Exc object into the exception_impl base class object:

========================================================================
exc:
Throw location unknown (consider using BOOST_THROW_EXCEPTION)
Dynamic exception type: some_exception
[tag_test_int*] = 42
========================================================================
*this:
Throw location unknown (consider using BOOST_THROW_EXCEPTION)
Dynamic exception type: exception_impl
std::exception::what: "blah"

IIRC, exception objects have to be copyable according to the standard and, disregarding possible optimizations, the result of a throw expression is copied. So boost's exceptions must be copyable and they certainly do not lose their information along the way. I must be missing something fairly obvious here.

What am I doing wrong?

like image 833
sbi Avatar asked Apr 16 '15 11:04

sbi


People also ask

Can a copy constructor throw an exception?

However, the copy constructor for an exception object still must not throw an exception because compilers are not required to elide the copy constructor call in all situations, and common implementations of std::exception_ptr will call a copy constructor even if it can be elided from a throw expression.

Does boost exception inherit from std exception?

As you said, boost::exception does not derive from std::exception .


1 Answers

Works perfecly fine for me:
(I had to add a default constructor to exception_impl)

#include <iostream>
#include <exception>
#include <boost/exception/all.hpp>

using std::cout;

class myException : public virtual boost::exception {

};

template <class T>
class exception_impl : public virtual std::exception, public T {
public:
    exception_impl() {}
    exception_impl(const T& ex) : T(ex) {}
    virtual const char* what() const throw() {return "blah";}
};

class some_exception : public myException {

};

struct tag_test_int;
typedef boost::error_info<tag_test_int,int> test_int_info;

void f()
{
    boost::throw_exception( exception_impl<some_exception>() << test_int_info(42) );
}

int main() {

    try {
        f();
    } catch (boost::exception& e) {
        cout << boost::diagnostic_information(e);
    }

    return 0;
}

Output:

Throw location unknown (consider using BOOST_THROW_EXCEPTION)
Dynamic exception type: N5boost16exception_detail10clone_implI14exception_implI14some_exceptionEEE
std::exception::what: blah
[P12tag_test_int] = 42

Compiled using:

  • g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
  • boost 1.55

I think the problem is that you output diagnostic information inside the constructor and tag_test_int is not set jet.

like image 125
WaeCo Avatar answered Nov 14 '22 22:11

WaeCo