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?
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.
As you said, boost::exception does not derive from std::exception .
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:
I think the problem is that you output diagnostic information inside the constructor and tag_test_int is not set jet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With