如何从 std::exception 到 std::nested_exception dynamic_cast?
How one can dynamic_cast from std::exception to std::nested_exception?
例如,我刚刚看到一个包含从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::exception
派生std::nested_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
来说是一种特殊和特殊的东西吗?或者,我是否可以在对象b
类型A
和类型没有公共基类的情况下成功dynamic_cast<A&>(b)
?
第一次,我以为这段代码不会被编译,因为 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_cast允许这样做
这一切都有据可查。我们正在讨论链接页面中的以下条款:
- 5) 如果表达式是指向多态类型 Base 的指针或引用,new_type是指向派生类型的指针或引用,则执行运行时检查:
(请注意,Base=std::exception
是多态的)
b) 否则,如果表达式指向/引用派生最多的对象的公共基,并且同时,派生
- 最多的对象具有派生类型的明确公共基类,则强制转换点的结果/引用该派生(这称为"侧播")。
由于您无法在编译时判断std::exception&
不是真正的MyExceptionWrapper
,因此您必须在运行时执行此操作。
如果你想避免在catch
块内意外重新抛出,只需写
auto *nested = dynamic_cast<std::nested_exception*>(&e);
相反。然后,您可以检查nullptr
以了解它是否成功。
.PPS。正如肖恩所建议的,上面的MyExceptionWrapper
实际上更有可能是throw_with_nested
生成的类型,但它具有相同的效果。
std::throw_with_nested 的文档指出,抛出的类型将从 std::nested_exception和您传入的异常类型公开派生。因此,在您的示例中,引发的异常在概念上具有以下类型:
class some_exception : public std::nested_exception, public std::runtine_exception
{
};
而且,由于std::runtime_exception
是从std_exception
衍生出来的,因此您可以抓住它。
- 为重写std::exception的库生成swig接口时出错
- 什么是 std::exception::what() 以及为什么要使用它?
- 为什么程序员同时使用 std::bad_alloc 和 std::exception.是否 std::例外 仅是不够的
- 请参阅在 Visual Studio 2019 中捕获 std::exception 时对函数模板实例化消息的引用
- 派生自 std::exception 的类的赋值运算符
- std::exception :使用虚函数和继承与变量
- 这段 C++ 代码的奇怪行为(std::wcout 和 std::exception)
- 如何从 std::exception 到 std::nested_exception dynamic_cast?
- 如何捕获 I/O 异常(确切地说是 I/O,而不是 std::exception)
- 在 CLI 中抛出 std::exception 会引发访问冲突
- 为什么 std::exception 会在 std::bad_alloc 之前捕获我的异常
- 为什么人们将虚拟关键字放在std :: exception :: what()的面前
- C++通过继承 std::exception 来创建新的异常
- 运行时异常消息而不扩展 std::exception
- 从 std::exception 类和类型标识继承
- 捕获并修改 std::exception 和子类,重新抛出相同的类型
- 使用预处理器宏构造用于抛出 std::exception 的信息消息的简单方法
- std::exception::What()的目的是什么
- std::exception's what() 返回"std::exception"
- 私有继承自 std::runtime_error 的类不会被捕获为 std::exception