Почему я теряю информацию о типе при использовании boost :: copy_exception? - PullRequest
2 голосов
/ 02 апреля 2012

Когда я использую boost::copy_exception для копирования исключения в exception_ptr, я теряю информацию о типе. Взгляните на следующий код:

try {
    throw std::runtime_error("something");
} catch (exception& e) {
    ptr = boost::copy_exception(e);
}
if (ptr) {
    try {
        boost::rethrow_exception(ptr);
    } catch (std::exception& e) {
        cout << e.what() << endl;
        cout << boost::diagnostic_information(e) << endl;
    }
}

Из этого я получаю следующий вывод:

N5boost16exception_detail10clone_implISt9exceptionEE
Dynamic exception type: boost::exception_detail::clone_impl<std::exception>
std::exception::what: N5boost16exception_detail10clone_implISt9exceptionEE

Так что в основном boost::copy_exception статически скопировал полученный аргумент.

Эта проблема решается, если вместо этого я выбрасываю свое исключение с boost::enable_current_exception, как это.

try {
    throw boost::enable_current_exception(std::runtime_error("something"));
} catch (...) {
    ptr = boost::current_exception();
}
if (ptr) {
    try {
        boost::rethrow_exception(ptr);
    } catch (std::exception& e) {
        cout << e.what() << endl;
        cout << boost::diagnostic_information(e) << endl;
    }
}

Проблема в том, что иногда исключения генерируются библиотекой, которая не использует boost::enable_current_exception. В этом случае, есть ли способ поместить исключение в exception_ptr, кроме перехвата каждого вида возможного исключения по одному и использовать boost::copy_exception на каждом?

1 Ответ

4 голосов
/ 02 апреля 2012

Это сделано специально, и ваш анализ верен: используется статический тип, а не динамический тип. Фактически, чтобы избежать этого сюрприза, boost::copy_exception стал std::make_exception_ptr во время процесса, который привел к C ++ 11. Таким образом, становится понятнее, что current_exception (будь то версия Boost или версия C ++ 11) - это то, что нужно для правильной записи текущего исключения. Я настоятельно рекомендую использовать BOOST_THROW_EXCEPTION или, по крайней мере, boost::throw_exception, когда дело доходит до использования исключений с поддержкой Boost.Exception в вашем коде.

Когда речь идет о стороннем коде, не существует другого решения, кроме того, которое вы уже упомянули, или какого-либо другого морального эквивалента (например, dynamic_cast) для различных конечных классов, составляющих иерархию типов исключений или иерархии. или typeid злоупотребление).

В этом отношении обработка исключений аналогична работе с одной или несколькими иерархиями полиморфных типов, и операция, которую вы пытаетесь в этом случае, представляет собой виртуальную копию, также известную как клонирование: либо ваш код навязчиво предназначен для поддержки это (как в случае использования, например, BOOST_THROW_EXCEPTION(e); вместо throw e;), или вы будете мучительно обходить дерево наследования. Обратите внимание, что вы можете, по крайней мере, рефакторировать эту боль только на одном сайте, так что в итоге вы получите, например,

try {
    third_party_api();
} catch(...) {
    ptr = catch_exceptions_from_api();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...