GCC(libstdc++)运行时如何决定在异常处于活动状态时终止()

Posted

技术标签:

【中文标题】GCC(libstdc++)运行时如何决定在异常处于活动状态时终止()【英文标题】:How GCC (libstdc++) runtime decides to terminate() while an exception is active 【发布时间】:2019-10-08 06:57:02 【问题描述】:

我们知道如果异常当前处于活动状态并且有另一个对 throw 的调用,则会调用 terminate()。

想了解是什么原因导致这与catch 块从内部执行throw 的情况有所不同?我假设如果一个 catch 块正在执行,它表示一个活动异常。

class exception_type

try ... throw obj; ... 
catch(exception_type& obj)
 ...
 ... 
 throw x;
 ...

从这个代码示例中,由于我们在 catch 块中有另一个 throw,它应该被动态封闭的 try 块中的另一个处理程序捕获。 所以这似乎是在catch 内有效使用throw。但是此时我们已经有一个异常活动。为什么不应该调用terminate()?或者换句话说,gcc 的 c++ 运行时如何准确地识别已经存在一个异常活动并且需要调用 terminate()。

【问题讨论】:

我说的是在 catch 块中投掷。它不必与最初抛出的异常对象相同。 @VTT 谢谢,这次我尝试了示例。 【参考方案1】:

一旦出现catched(当控制进入catch 部分时),异常就会停止“活动”。

【讨论】:

谢谢 +1,我现在可以回忆起论文“IA-64 的 C++ 异常处理”中的详细信息,您介意我在自己对问题的详细回答中解释这一点吗? @ultimatecause 当然,我不介意。毕竟这是你的问题。【参考方案2】:

这个答案的功劳归于@HolyBlackCat,他在他的回答中暗示了这一点。

throw 的响应是一个复杂的过程,其中 C++ 运行时需要执行几个不同的操作。虽然实际过程可能由运行时的实现定义,但很少有东西可以共同理解。 This paper 可以提供更多信息。请参阅第 3.3 节。

在为throw 提供服务的过程中,将开始搜索适当的catch。这本身可能会导致当前堆栈帧的展开。展开堆栈帧的副作用是调用当前帧中对象的相应析构函数。再次调用析构函数的这个动作将运行时降落在用户的代码区域(不安全)。完成后,我们再次进入运行时的区域(更安全)。

最后,当输入一个合适的catch 时,活动异常被销毁并开始执行处理程序的代码。由于这个原因,throw 如问题所示,不会遇到任何活动异常。

这也解释了为什么我们不应该 throw 一个超出范围的析构函数的异常。实际上,在析构函数中有一个 try....catch(...) 块以防止任何不良的 terminate() 事件是一个好习惯。

【讨论】:

以上是关于GCC(libstdc++)运行时如何决定在异常处于活动状态时终止()的主要内容,如果未能解决你的问题,请参考以下文章

为啥异常不适用于 OSX 上的 gcc7 和 -static-libgcc?

Linux升级gcc

Linux From Scratch(LFS11.0)编译交叉工具链 - GCC-11.2.0 中的 Libstdc++,第一遍

GCC libstdc++ 配置文件模式的替代方案

调用 mbtowc() 时 gcc 如何决定宽字符集?

如何静态链接到 libstdc++.喜欢升级的GCC的朋友快来看看