我刚看到包含从std::exception
到std::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::exception
和std::nested_exception
来说是一种特殊和特殊的东西吗?或者,我可以创建另一个成功的dynamic_cast<A&>(b)
,其中类型A
和对象类型b
没有共同的基类吗?
答案 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
,您可以抓住它。