16.3 异常发生时的内存管理
异常的发生使得程序的流程发生改变,原有的一些变量和类对象等的撤销操作会不会受影响,是否会有内存泄露,这是本节要讨论的内容。
16.3.1 堆栈解退
在函数一章中提到,当函数执行结束后,在其中声明的局部变量会被自动撤销,自动类对象的析构函数会被自动执行并释放资源。如果函数因为异常而终止,从throw语句到try语句之间所有的局部变量会被自动撤销,自动类对象的析构函数被自动执行,这种机制叫做堆栈引退。如示例代码16.11所示。
代码16.11 堆栈解退示例StackSample
<———————————-文件名:example1611.cpp———————————————> 01 #include<iostream> 02 using namespace std; 03 class MyEx//MyEx类定义 04 { 05 int num; 06 public: 07 MyEx(int n) 08 { 09 num=n; 10 } 11 ~MyEx() 12 { 13 cout<<num<<",MyExX析构"<<endl; 14 } 15 }; 16 void fun() 17 { 18 int num=8; 19 throw"error";//抛出异常 20 } 21 void call() 22 { 23 MyEx m1(5);//try块外定义的MyEx类对象 24 try 25 { 26 MyEx m2(6);//try块内定义的MyEx类对象 27 fun(); 28 } 29 catch(const char*s) 30 { 31 cout<<s<<endl; 32 } 33 } 34 int main() 35 { 36 call(); 37 return 0; 38 }
输出结果如下所示。
6,MyExX析构 error 5,MyExX析构
【代码解析】当fun函数执行到第19行的throw语句抛出异常时,fun函数终止,此时,fun函数内的int型变量num被撤销,但撤销的不只是fun函数内的变量,从fun函数的throw语句到try块之间的局部变量都会被撤销,包括第26行的try块内定义的MyEx类对象m2,所以输出结果的第一行为“6,MyExX”,而后程序转到匹配catch块执行相应操作,输出“error”,在catch块执行结束后,call函数结束,call函数中定义的MyEx对象m1被撤销,其析构函数被调用。