为什么我的程序在析构函数抛出异常时终止?

时间:2009-12-11 07:52:39

标签: c++ exception destructor

我不明白为什么如果存在活动异常,那么如果再次引发异常,则会导致程序终止。有人可以解释一下吗?

6 个答案:

答案 0 :(得分:15)

它应该做什么?它不能“双重捕捉”或任何东西,也不能简单地忽略它。该标准指定如果在堆栈展开期间另一个异常转义,则应调用terminate

C++ FAQ中有更多讨论。一个“解决方案”是将析构函数代码包装在try / catch块中,并且不要让异常转义。

另一个是提出某种自定义异常链方案。您可以执行上述操作,但不是忽略异常,而是将其附加到当前抛出的异常,并在catch站点手动处理。

我认为最好的解决方案是尝试从析构函数中删除异常代码。

答案 1 :(得分:3)

原因很简单......如果在异常传播期间抛出异常,那么应该传播哪个异常?原始异常还是新异常?如果传播然后处理新的异常,程序将如何知道发生了另一个异常?或者原始异常会被忽略吗?这和许多其他复杂情况导致了一个简单的规则,即一次只能传播一个异常,多次失败将导致应用程序被终止。

答案 2 :(得分:3)

标准(15.2.3):

  

为从try块到throw-expression的路径构造的自动对象调用析构函数的过程称为“堆栈展开”。[注意:如果在堆栈展开期间调用的析构函数以异常退出,则终止是叫(except.terminate)。所以析构函数通常应该捕获异常,而不是让它们从析构函数中传播出来。   ---结束说明]

基本上C ++(与大多数其他流行的编程语言一样)对使用异常处理多个错误没有很好的支持。作为一种机制,例外在这方面是完全不足的。

常见问题解答对How to handle a destructor that fails?

有一些建议

Stroustroup就此问题(TCPL 14.7):

  

terminate() 的原因是,为了不那么微妙的错误处理技术,有时必须放弃异常处理。例如, terminate() 可用于中止进程或重新初始化系统。当异常处理机制实现的错误恢复策略失败时, terminate() 的意图是应用的一个重大措施,是时候去另一层次的容错策略。

另见前面关于SO的相关讨论:基本上是any question about exceptions and destructors

答案 3 :(得分:1)

答案 4 :(得分:1)

当您throw异常时,它会一直展开堆栈,直到它到达适当的catch块。作为堆栈展开过程的一部分,将为每个帧的范围内的每个对象调用析构函数。

现在,当析构函数在这种情况下抛出异常时,存在一个两难问题 - catch块是程序应该停止的?原来的例外,还是新的例外?无论哪种方式,都涉及到未经处理的异常。

程序不擅长做出这样的决定,所以标准说它甚至不会尝试解决问题而只是放弃。

查看the FAQ-Lite entry解释此确切情况以获取更多详细信息。

答案 5 :(得分:1)

Effective C++

Item 8表示您不应该允许异常离开析构函数。