【问题标题】:How one can dynamic_cast from std::exception to std::nested_exception?如何从 std::exception 到 std::nested_exception 的 dynamic_cast?
【发布时间】:2018-04-25 08:53:41
【问题描述】:

例如,我刚刚看到一个包含从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&lt;A&amp;&gt;(b) 类型A 和对象类型b 没有公共基类吗?

【问题讨论】:

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


    【解决方案1】:

    一开始,我以为这段代码不会被编译,因为 std::nested_exception 不是从 std::exception 派生的

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

    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 cast,因为它必须在运行时检查动态类型。如果您想在编译时执行静态检查,您正在寻找 static cast。

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

    这都是well documented。我们正在讨论链接页面中的以下条款:

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

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

      • b) 否则,如果表达式指向/引用最派生对象的公共基类,并且同时,最派生对象具有 Derived 类型的明确公共基类,则转换的结果指向/引用该派生(这称为“边播”。)

    由于您无法在编译时判断 std::exception&amp; 不是真正的 MyExceptionWrapper,因此您必须在运行时执行此操作。


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

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

    相反。然后你可以检查nullptr是否成功。


    PPS。正如肖恩所说,上面的MyExceptionWrapper确实更有可能是throw_with_nested生成的类型,但效果是一样的。

    【讨论】:

    • 这是旁观者,而不是垂头丧气。
    • 你说的很对,我贴错了项目符号。谢谢!
    【解决方案2】:

    std::throw_with_nested 的文档指出,抛出的类型将公开来自 std::nested_exception 您传入的异常类型。因此,在您的示例中,抛出的异常在概念上具有类型:

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

    而且,由于std::runtime_exception 是从std_exception 派生的,因此您可以抓住它。

    【讨论】:

      猜你喜欢
      • 2015-04-17
      • 2012-06-12
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多