Могу ли я скопировать-создать boost :: exception с информацией об ошибке?

Рассмотрим следующий код, использующий класс исключений boost:

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";}
};

(На самом деле этот код является более сложным. Например, exception_impl происходит только от std::exception если последний уже не является прямым или косвенным базовым классом Exc, Но это только отвлекает меня от проблемы, поэтому я пропустил ее.)


Учитывая это, теперь я могу получить свои собственные классы исключений:

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

И использовать их:

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) );
}

Однако оказывается, что полученное исключение не имеет test_int_info объект. Так что я изменил exception_impl конструктор для предоставления некоторой диагностической информации:

    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";
}

Это действительно показывает, что информация теряется, когда я копирую Exc возражать в exception_impl объект базового класса:

================================================== ======================
возб:
Бросить местоположение неизвестно (рассмотрите возможность использования BOOST_THROW_EXCEPTION)
Тип динамического исключения: some_exception
[tag_test_int *] = 42
================================================== ======================
*этот:
Бросить местоположение неизвестно (рассмотрите возможность использования BOOST_THROW_EXCEPTION)
Тип динамического исключения: exception_impl
std :: исключение :: что: "бла"

IIRC, объекты исключения должны быть копируемыми в соответствии со стандартом, и, независимо от возможных оптимизаций, результат выражения броска копируется. Так что исключения буста должны быть копируемыми, и они, безусловно, не потеряют свою информацию по пути. Должно быть, я упускаю что-то довольно очевидное

Что я делаю неправильно?

12

Решение

Работает совершенно нормально для меня:
(Мне пришлось добавить конструктор по умолчанию в 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;
}

Выход:

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

Скомпилировано с использованием:

  • g ++ (Ubuntu 4.9.2-0ubuntu1 ~ 14.04) 4.9.2
  • повысить 1,55

Я думаю, что проблема в том, что вы выводите диагностическую информацию внутри конструктора, а tag_test_int не устанавливает jet.

3

Другие решения