第8集析构函数中抛出的异常

第8集析构函数中抛出的异常,第1张

第8集析构函数中抛出的异常,第2张

前两篇文章讨论了对象在构造过程中(构造函数)和运行过程中(成员函数)出现异常时的处理情况,本文将讨论最后一种情况,当异常发生在对象的析构销毁过程中时,又会有什么不同呢?主人公阿愚在此可以非常有把握地告诉大家,这将会有大大的不同,而且处理不善还将会毫不留情地影响到软件系统的可靠性和稳定性,后果非常严重。不危言耸听了,看正文吧!
析构函数在什么时候被调用执行?

  对于C++程序员来说,这个问题比较简单,但是比较爱唠叨的阿愚还是建议应该在此再提一提,也算回顾一下C++的知识,而且这将对后面的讨论和理解由一定帮助。先看一个简单的示例吧!如下:
class MyTest_Base
{
public:
virtual ~ MyTest_Base ()
{
cout << "销毁一个MyTest_Base类型的对象"<< endl;
}
};

void main()
{
try
{
// 构造一个对象,当obj对象离开这个作用域时析构将会被执行
MyTest_Base obj;
}
catch(...)
{
cout << "unknow exception"<< endl;
}
}
  编译运行上面的程序,从程序的运行结果将会表明对象的析构函数被执行了,但什么时候被执行的呢?按C++标准中规定,对象应该在离开它的作用域时被调用运行。实际上各个厂商的C++编译器也都满足这个要求,拿VC来做个测试验证吧!,下面列出的是刚刚上面的那个小示例程序在调试时拷贝出的相关程序片段。注意其中obj对象将会在离开try block时被编译器插入一段代码,隐式地来调用对象的析构函数。如下:

325: try
326: {
00401311 mov dword ptr [ebp-4],0
327: // 构造一个对象,当obj对象离开这个作用域时析构将会被执行
328: MyTest_Base obj;
00401318 lea ecx,[obj]
0040131B call @ILT+40(MyTest_Base::MyTest_Base) (0040102d)
329:
330: } // 瞧下面,编译器插入一段代码,隐式地来调用对象的析构函数
00401320 lea ecx,[obj]
00401323 call @ILT+15(MyTest_Base::~MyTest_Base) (00401014)
331: catch(...)
00401328 jmp __tryend$_main$1 (00401365)
332: {
333: cout << "unknow exception"<< endl;
0040132A mov esi,esp
0040132C mov eax,[__imp_?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z (0041610c)
00401331 push eax
00401332 mov edi,esp
00401334 push offset string "unknow exception" (0041401c)
00401339 mov ecx,dword ptr [__imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (00416124)
0040133F push ecx
00401340 call dword ptr [__imp_??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z (004
00401346 add esp,8
00401349 cmp edi,esp
0040134B call _chkesp (004016b2)
00401350 mov ecx,eax
00401352 call dword ptr [__imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01
00401358 cmp esi,esp
0040135A call _chkesp (004016b2)
334: }
0040135F mov eax,offset __tryend$_main$1 (00401365)
00401364 ret
335: }
析构函数中抛出的异常
1、仍然是先看示例,如下:
class MyTest_Base
{
public:
virtual ~ MyTest_Base ()
{
cout << "开始准备销毁一个MyTest_Base类型的对象"<< endl;
// 注意:在析构函数中抛出了异常
throw std::exception("在析构函数中故意抛出一个异常,测试!");
}
void Func() throw()
{
throw std::exception("故意抛出一个异常,测试!");
}
void Other() {}
};

void main()
{
try
{
// 构造一个对象,当obj对象离开这个作用域时析构将会被执行
MyTest_Base obj;

obj.Other();
}
catch(std::exception e)
{
cout << e.what() << endl;
}
catch(...)
{
cout << "unknow exception"<< endl;
}
}

   程序运行的结果是:
  开始准备销毁一个MyTest_Base类型的对象
  在析构函数中故意抛出一个异常,测试!
  从上面的程序运行结果来看,并没有什么特别的,在程序中首先是构造一个对象,当这个对象在离开它的作用域时,析构函数被调用,此时析构函数中抛出一个 std::exception类型的异常,因此后面的catch(std::exception e)块捕获住这个异常,并打印出异常错误信息。这个过程好像显现出,发生在析构函数中的异常与其它地方发生的异常(如对象的成员函数中)并没有什么太大的不同,除了析构函数是隐式调用的以外,但这也丝毫不会影响到异常处理的机制呀!那究竟区别何在?玄机何在呢?继续往下看吧!
  2、在上面的程序基础上做点小的改动,程序代码如下:
void main()

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » 第8集析构函数中抛出的异常

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情