在C ++中抛出后是否会调用析构函数?

时间:2011-11-29 13:23:21

标签: c++ exception-handling try-catch raii

我运行了一个示例程序,确实调用了堆栈分配对象的析构函数,但这是否由标准保证?

3 个答案:

答案 0 :(得分:56)

是的,保证(如果捕获了异常),直到调用析构函数的订单

  

C ++ 11 15.2构造函数和析构函数[except.ctor]

     

1当控件从throw-expression传递给处理程序时,将为所有人调用析构函数   输入try块后构造的自动对象。该   自动对象以完成的相反顺序销毁   他们的建筑。

此外,如果在对象构造期间抛出异常,则保证部分构造的对象的子对象被正确销毁:

  

2任何存储持续时间的对象,其初始化或   如果异常将具有析构函数,则终止销毁   为所有完全构建的子对象执行(不包括   类似联合类的变体成员),即子对象的变体成员   主要构造函数(12.6.2)已完成执行和   析构函数尚未开始执行。同样,如果   对象的非委托构造函数已完成执行并且a   委托该对象的构造函数以异常退出   将调用object的析构函数。如果对象是在一个中分配的   new-expression,匹配解除分配函数(3.7.4.2,5.3.4,   12.5),如果有的话,被调用来释放对象占用的存储空间。

整个过程称为“堆栈展开”:

  

3为构造的自动对象调用析构函数的过程   在从try块到throw-expression的路径上称为“堆栈”   展开。“如果在堆栈展开期间调用的析构函数退出   一个例外,调用std :: terminate(15.5.1)。

堆栈展开是广泛使用的称为Resource Acquisition Is Initialization (RAII)的技术的基础。

请注意,如果未捕获异常,则不必执行堆栈展开。在这种情况下,是否完成堆栈展开的实现。但是,无论是否完成堆栈展开,在这种情况下,您都可以保证最终调用std::terminate

  

C ++ 11 15.5.1 std :: terminate()函数[except.terminate]

     

2 ...在没有找到匹配处理程序的情况下,   它是实现定义的,无论在调用std::terminate()之前是否展开堆栈。

答案 1 :(得分:6)

是的,保证在堆栈展开时调用析构函数,包括因抛出异常而展开。只有少数几个例外,你必须要记住:

  • 如果在构造函数中抛出异常,则不会调用类的析构函数。
  • 如果在构造初始化列表catch块中捕获异常,则会自动重新抛出异常。

答案 2 :(得分:0)

如果引发了异常,则通常cpp操作将继续。这包括析构函数和堆栈弹出。但是,如果未捕获到异常,则不能保证堆栈弹出。

我的移动编译器也无法捕获空投或空投。

示例:

#include <Jav/report.h>

int main()
{
 try { throw; }
 catch(...) { rep("I bet this is not caught"); }
 }