当我使用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
之外?
答案 0 :(得分:4)
这是设计使然,您的分析是正确的:使用静态类型,而不是动态类型。实际上,为了避免这种意外,boost::copy_exception
在导致C ++ 11的过程中变为std::make_exception_ptr
。这样,current_exception
(无论是Boost版本还是C ++ 11版本)用于正确捕获当前异常都是正确的。在您的代码中使用Boost.Exception启用的异常时,我强烈建议您使用BOOST_THROW_EXCEPTION
或至少boost::throw_exception
。
当谈到第三方代码时,除了你已经提到的解决方案之外没有其他解决方案,或者其他一些道德等价物(如dynamic_cast
- 构成异常类型层次结构的不同叶类或层次结构,或typeid
滥用)。
在这方面,异常处理与使用多态类型的一个或多个层次结构相同,在这种情况下您尝试的操作是虚拟副本,也称为克隆:要么您的代码是侵入式设计以支持(就像使用例如BOOST_THROW_EXCEPTION(e);
而不是throw e;
)的情况一样,或者你将痛苦地走向继承树。请注意,您至少可以将这种痛苦重构为一个站点,这样您最终会得到这样的结果。
try {
third_party_api();
} catch(...) {
ptr = catch_exceptions_from_api();
}