Нет правильного способа сделать это со стандартными исключениями в C ++ 03, потому что они предназначены для полиморфного использования, но не могут быть клонированы.Так что если вы поймаете std::exception const& e
, вы сможете сохранить копию, но это приведет к разрезанию, потере всей полезной информации.Вы должны не хранить указатель или ссылку на исключение, потому что его время жизни заканчивается, как только выходит из предложения catch
(при условии, что вы не выбрасываете исходное исключение).
Вы могли бы обойти это ограничение, если бы знали каждый тип, который можно бросить, и тестировали их все, но это не очень хороший дизайн (то есть он подрывает полиморфизм).Имеет смысл написать собственный базовый класс исключений, который можно клонировать, и поймать его.У вас все еще есть проблема, если вы поймаете std::exception
, полученный из чужого кода.
В этот момент я вынужден упомянуть Boost.Exception .Это облегчает написание вашей собственной иерархии исключений и предоставляет различные утилиты, среди которых boost::exception_ptr
.Затем вы можете сделать:
typedef boost::error_info<struct tag_nested_exception, boost::exception_ptr>
nested_exception;
// ...
catch(...) {
// better: use BOOST_THROW_EXCEPTION
throw your_exception_type() << nested_exception( boost::current_exception() );
}
Это настолько полезно, что boost::diagnostic_info
поддерживает его и отображает для вас вложенное исключение (оно недокументировано).Было даже предложено, чтобы этот nested_exception
typedef
тоже был частью библиотеки;тем временем это легко написать самостоятельно.
Не ожидайте магии, хотя: boost::current_exception
'захватывает' активное исключение (мелкий шрифт или его клон), хорошо, только если использовался сайт броска boost::enable_current_exception
.(Функционально это моральный эквивалент использования базового класса исключений, который можно клонировать).Если этого не произойдет, это не даст сбоя, но некоторая информация может быть потеряна.
В качестве последнего замечания, знайте, что дизайн Boost.Exception был принят для C ++ 0x.Таким образом, следующее правильно сохраняет активное исключение, ни с одним из предупреждений boost::current_exception
, так как оно имеет языковую поддержку:
// you can still use Boost.Exception:
typedef boost::error_info<struct tag_nested_exception, std::exception_ptr>
nested_exception;
// ...
catch(...) {
// e has type std::exception_ptr
auto e = std::current_exception();
// internally store the std::exception_ptr
throw your_exception_type(e);
// or with Boost
BOOST_THROW_EXCEPTION( your_exception_type() << nested_exception(e) );
}
Существует также тип std::nested_exception
, который можно очень легко использовать, например, так:
catch(...) {
// throws an unspecified type derived from your_exception_type
// and std::nested_exception
std::throw_with_nested(your_exception_type());
}