如何将 dynamic_cast 从 std::exception 转换为 std::nested_exception?

xyl*_*per 3 c++ dynamic-cast exception nested-exceptions c++11

例如,我刚刚看到了一个包含 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;
}
Run Code Online (Sandbox Code Playgroud)

第一次,我认为这段代码不会被编译,因为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::exceptionand 来说有什么特别的和特殊的std::nested_exception吗?或者,我可以dynamic_cast<A&>(b)A对象的类型和类型b没有公共基类的情况下取得另一个成功吗?

Use*_*ess 5

第一次,我认为这段代码不会被编译,因为 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
};
Run Code Online (Sandbox Code Playgroud)

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

在上述情况下dynamic_cast,必须在运行时检查您std::exception是否真的是 a MyExceptionWrapper,在这种情况下它也是a std::nested_exception

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

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

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

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

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

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

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


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

auto *nested = dynamic_cast<std::nested_exception*>(&e);
Run Code Online (Sandbox Code Playgroud)

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


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