dynamic_cast如何从std::exception变成std::nested_exception?
How one can dynamic_cast from std::exception to std::nested_exception?
我刚刚看到一个包含 dynamic_cast 从 std::exception
到 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
和 std::nested_exception
来说是不是一件特别的事情?或者,我可以在类型 A
和对象类型 b
没有公共基础 class 的情况下创建另一个成功的 dynamic_cast<A&>(b)
吗?
At the very first time, I thought this code won't be compiled because std::nested_exception is not derived from std::exception
这还不够 - std::nested_exception
旨在用作混音 class,如
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
};
expected dynamic_cast would do static check of inheritance but I was wrong
在上述情况下 dynamic_cast
必须在运行时 检查 你的 std::exception
是否 真的 MyExceptionWrapper
,在这种情况下,它 也是 一个 std::nested_exception
。
这就是为什么它被称为动态 cast,因为它必须在运行时检查动态类型。如果你想在编译时执行静态检查,你正在寻找 static cast.
Although I couldn't find related standard specification which explicitly mentions that dynamic_cast allows this
这就是全部 well documented。我们正在讨论链接页面中的以下子句:
- 5) If expression is a pointer or reference to a polymorphic type Base, and new_type is a pointer or reference to the type Derived a run-time check is performed:
(注意Base=std::exception
是多态的)
- b) Otherwise, if expression points/refers to a public base of the most derived object, and, simultaneously, the most derived object has an unambiguous public base class of type Derived, the result of the cast points/refers to that Derived (This is known as a "sidecast".)
由于您无法在编译时判断 std::exception&
不是真正的 MyExceptionWrapper
,因此您必须在运行时执行此操作。
PS。如果你想避免在 catch
块内意外重新抛出,只需写
auto *nested = dynamic_cast<std::nested_exception*>(&e);
相反。然后你可以检查nullptr
,看看是否成功。
PPS。正如肖恩所说,上面的 MyExceptionWrapper
确实更可能是由 throw_with_nested
生成的类型,但它具有相同的效果。
std::throw_with_nested states that the type thrown will publicly dervive from both std::nested_exception和您传入的异常类型的文档。因此,在您的示例中,抛出的异常在概念上具有以下类型:
class some_exception : public std::nested_exception, public std::runtine_exception
{
};
而且,由于 std::runtime_exception
是从 std_exception
派生出来的,所以您可以捕捉到它。
我刚刚看到一个包含 dynamic_cast 从 std::exception
到 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
和 std::nested_exception
来说是不是一件特别的事情?或者,我可以在类型 A
和对象类型 b
没有公共基础 class 的情况下创建另一个成功的 dynamic_cast<A&>(b)
吗?
At the very first time, I thought this code won't be compiled because std::nested_exception is not derived from std::exception
这还不够 - std::nested_exception
旨在用作混音 class,如
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
};
expected dynamic_cast would do static check of inheritance but I was wrong
在上述情况下 dynamic_cast
必须在运行时 检查 你的 std::exception
是否 真的 MyExceptionWrapper
,在这种情况下,它 也是 一个 std::nested_exception
。
这就是为什么它被称为动态 cast,因为它必须在运行时检查动态类型。如果你想在编译时执行静态检查,你正在寻找 static cast.
Although I couldn't find related standard specification which explicitly mentions that dynamic_cast allows this
这就是全部 well documented。我们正在讨论链接页面中的以下子句:
- 5) If expression is a pointer or reference to a polymorphic type Base, and new_type is a pointer or reference to the type Derived a run-time check is performed:
(注意Base=std::exception
是多态的)
- b) Otherwise, if expression points/refers to a public base of the most derived object, and, simultaneously, the most derived object has an unambiguous public base class of type Derived, the result of the cast points/refers to that Derived (This is known as a "sidecast".)
由于您无法在编译时判断 std::exception&
不是真正的 MyExceptionWrapper
,因此您必须在运行时执行此操作。
PS。如果你想避免在 catch
块内意外重新抛出,只需写
auto *nested = dynamic_cast<std::nested_exception*>(&e);
相反。然后你可以检查nullptr
,看看是否成功。
PPS。正如肖恩所说,上面的 MyExceptionWrapper
确实更可能是由 throw_with_nested
生成的类型,但它具有相同的效果。
std::throw_with_nested states that the type thrown will publicly dervive from both std::nested_exception和您传入的异常类型的文档。因此,在您的示例中,抛出的异常在概念上具有以下类型:
class some_exception : public std::nested_exception, public std::runtine_exception
{
};
而且,由于 std::runtime_exception
是从 std_exception
派生出来的,所以您可以捕捉到它。