如何从std :: exception动态广播到std :: nested_exception?

时间:2018-04-25 08:53:41

标签: c++ c++11 exception dynamic-cast nested-exceptions

我刚看到包含从std::exceptionstd::nested_exception的dynamic_cast的代码,例如,

try {
    std::throw_with_nested(std::runtime_error("error"));
} catch (std::exception &e) {
    auto &nested = dynamic_cast<std::nested_exception&>(e);
    std::cout << "ok" << std::endl;
}

这是第一次,我认为这段代码不会被编译,因为std::nested_exception 未派生来自std::exception,我期待dynamic_cast会做静态的继承检查,但我错了。

虽然我找不到明确提到dynamic_cast允许这样做的相关标准规范,但我确认所有三个主要编译器(clang / gcc / msvc)允许dynamic_cast在完全不相关的类型之间

但仍然std::nested_exception不是来自std::exception,所以我认为dynamic_cast会抛出bad_alloc例外而"ok"永远不会打印出来。我又错了。

现在,我想知道这是如何运作的。这对于std::exceptionstd::nested_exception来说是一种特殊和特殊的东西吗?或者,我可以创建另一个成功的dynamic_cast<A&>(b),其中类型A和对象类型b没有共同的基类吗?

2 个答案:

答案 0 :(得分:4)

  

在第一次,我认为这段代码不会被编译,因为std :: nested_exception不是从std :: exception

派生的

这还不够 - std::nested_exception旨在用作mixin类,例如

struct MyExceptionWrapper: public std::exception, std::nested_exception
{
    // an 3rd-party component of my library threw
    // and I want to wrap it with a common interface
};
  

期望dynamic_cast会对继承进行静态检查,但我错了

在上述情况下,dynamic_cast必须在运行时检查 std::exception 是否 MyExceptionWrapper,在这种情况下它一个std::nested_exception

这就是它被称为 dynamic 强制转换的原因,因为它必须在运行时检查动态类型。如果您想在编译时执行静态检查,那么您正在寻找 static 强制转换。

  

虽然我找不到相关的标准规范明确提到dynamic_cast允许这个

这都是well documented。我们将从链接页面讨论以下条款:

  
    
        
  • 5)如果expression是多态类型Base的指针或引用,new_type是Derived类型的指针或引用,则执行运行时检查:
  •     
  

(请注意Base=std::exception 多态的)

  
    
        
    •     
    • b)否则,如果表达式points /引用最派生对象的公共基础,并且同时,最派生的对象具有Derived类型的明确公共基类,则转换点的结果/指的是派生(这被称为&#34; sidecast&#34;。)
    •     
  •     
  

由于您无法在编译时告诉std::exception&实际上不是MyExceptionWrapper,因此您必须在运行时执行此操作。

PS。如果你想避免在catch区块内意外重新抛出,只需写下

auto *nested = dynamic_cast<std::nested_exception*>(&e);

代替。然后,您可以检查nullptr以确定它是否成功。

PPS。正如Sean所说,上面的MyExceptionWrapper实际上更可能是由throw_with_nested生成的类型,但它具有相同的效果。

答案 1 :(得分:1)

std::throw_with_nested的文档指出,抛出的类型会从std::nested_exception 公开发送您传入的异常类型。因此,在您的示例中,从概念上抛出的异常具有以下类型:

class some_exception : public std::nested_exception, public std::runtine_exception
{

};

而且,由于std::runtime_exception来自std_exception,您可以抓住它。