首页 > 解决方案 > 如何从 std::exception 到 std::nested_exception 的 dynamic_cast?

问题描述

我刚刚看到一个包含 dynamic_cast from std::exceptionto的代码std::nested_exception,例如,

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::exception这对于and来说是不是很特别std::nested_exception?或者,我可以在对象dynamic_cast<A&>(b)类型A和类型b没有共同基类的情况下成功吗?

标签: c++c++11exceptiondynamic-castnested-exceptions

解决方案


一开始,我认为这段代码不会被编译,因为 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检查您是否真的是 a ,在这种情况下它也是a 。std::exceptionMyExceptionWrapperstd::nested_exception

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

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

这都是有据可查的。我们正在讨论链接页面中的以下条款:

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

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

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

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


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

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

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


聚苯乙烯。正如 Sean 所暗示的,MyExceptionWrapper上面确实更有可能是由 生成的类型throw_with_nested,但它具有相同的效果。


推荐阅读