C++中出现异常时销毁局部对象的顺序

C++中出现异常时销毁局部对象的顺序

程序清单 28.4 表明,引发异常时将对局部对象调用析构函数。
如果因出现异常而被调用的析构函数也引发异常,将导致应用程序异常终止。

每当您使用 throw 引发异常时,编译器都将查找能够处理该异常的 catch(Type)。异常处理逻辑首
先检查引发异常的代码是否包含在 try 块中, 如果是, 则查找可处理这种异常的 catch(Type)。 如果 throw
语句不在 try 块内,或者没有与引发的异常兼容的 catch( ),异常处理逻辑将继续在调用函数中寻找。
因此,异常处理逻辑沿调用栈向上逐个地在调用函数中寻找,直到找到可处理异常的 catch(Type)。在
退栈过程的每一步中,都将销毁当前函数的局部变量,因此这些局部变量的销毁顺序与创建顺序相反。
程序清单 28.4 演示了这一点

0: #include <iostream>
1: using namespace std;
2:
3: struct StructA
4: {
5: StructA() {cout << "StructA constructor" << endl; }
6: ~StructA() {cout << "StructA destructor" << endl; }
7: };
8:
9: struct StructB
10: {
11: StructB() {cout << "StructB constructor" << endl; }
12: ~StructB() {cout << "StructB destructor" << endl; }
13: };
14:
15: void FuncB() // throws
16: {
17: cout << "In Func B" << endl;
18: StructA objA;
19: StructB objB;
20: cout << "About to throw up!" << endl;
21: throw "Throwing for the heck of it";
22: }
23:
24: void FuncA()
25: {
26: try
27: {
28: cout << "In Func A" << endl;
29: StructA objA;
30: StructB objB;
31: FuncB();
32: cout << "FuncA: returning to caller" << endl;
33: }
34: catch(const char* exp)
35: {
36: cout << "FuncA: Caught exception: " << exp << endl;
37: cout << "Handled it, will not throw to caller" << endl;
38: // throw; // uncomment this line to throw to main()
39: }
40: }
41:
42: int main()
43: {
44: cout << "main(): Started execution" << endl;
45: try
46: {
47: FuncA();
48: }
49: catch(const char* exp)
50: {
51: cout << "Exception: " << exp << endl;
52: }
53: cout << "main(): exiting gracefully" << endl;
54: return 0;
55: }

输出:
main(): Started execution
In Func A
StructA constructor
StructB constructor
In Func B
StructA constructor
StructB constructor
About to throw up!

StructB destructor
StructA destructor
StructB destructor
StructA destructor
FuncA: Caught exception: Throwing for the heck of it
Handled it, will not throw to caller
main(): exiting gracefully
分析:
在程序清单 28.4 中, main( )调用了 FuncA( ), FuncA( )调用了 FuncB( ),而 FuncB( )引发异常,如
第 21 行所示。函数 FuncA( )和 main( )都能处理这种异常,因为它们都包含 catch(const char*)。引发异
常的 FuncB( )没有 catch( )块,因此 FuncB( )引发的异常将首先由 FuncA( )中的 catch 块(第 34~39 行)
处理,因为是 FuncA( )调用了 FuncB( )。注意到 FuncA( )认为这种异常不严重,没有继续将其传播给
main( )。因此,在 main( )看来,就像没有问题发生一样。如果解除对第 38 行的注释,异常将传播给
FuncA 的调用者,即 main( )也将收到这种异常。
输出指出了对象的创建顺序(与实例化它们的代码的排列顺序相同),还指出了引发异常后对象被
销毁的顺序(与实例化顺序相反)。不仅在引发异常的 FuncB( )中创建的对象被销毁,在调用 FuncB( )
并处理异常的 FuncA( )中创建的对象也被销毁。

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值