使用boost :: copy_exception时为什么会丢失类型信息?

时间:2012-04-02 08:59:53

标签: c++ exception boost

当我使用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 个答案:

答案 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();
}