第14集再探C++中异常的rethrow

第14集再探C++中异常的rethrow,第1张

第14集再探C++中异常的rethrow,第2张

在相遇篇中的《第5集 C++的异常rethrow》文章中,已经比较详细讨论了异常重新被抛出的处理过程。但是有一点却并没有叙述到,那就是C++异常重新被抛出时(rethrow),异常对象的构造、传递和析构销毁的过程会有哪些变化和不同之处。为了精益求精,力求对每一个细节都深入了解和掌握,下面再全面阐述一下各种不同组合情况下的异常构造和析构的过程。

  大家现在知道,异常的重新被抛出有两种方式。其一,由于当前的catch block块处理不了这个异常,所以这个异常对象再次原封不动地被重新抛出;其二,就是在当前的catch block块处理异常时,又激发了另外一个异常的抛出。另外,由于异常对象的传递方式有三种:传值、传引用和传指针。所以实际上这就导致了有6种不同的组合情况。下面分别阐述之。

异常对象再次原封不动地被重新抛出

  1、首先讨论异常对象“按值传递”的方式下,异常对象的构造、传递和析构销毁的过程有何不同之处?毫无疑问,在异常被重新被抛出时,前面的一个异常对象的构造和传递过程肯定不会被影响,也即“按值传递”的方式下,异常被构造了3次,异常对象被“按值传递”到这个catch block中。实际上,需要研究的是,当异常被重新被抛出时,这个异常对象是否在离开当前的这个catch block域时会析构销毁掉,并且这个异常对象是否还会再次被复制构造?以及重新被抛出的异常对象按什么方式被传递?看如下例程:

class MyException
{
public:
MyException (string name="none") : m_name(name)
{
number = ++count;
cout << "构造一个MyException异常对象,名称为:"<}

MyException (const MyException& old_e)
{
m_name = old_e.m_name;
number = ++count;

cout << "拷贝一个MyException异常对象,名称为:"<}

operator= (const MyException& old_e)
{
m_name = old_e.m_name;
number = ++count;

cout << "赋值拷贝一个MyException异常对象,名称为:"<}

virtual ~ MyException ()
{
cout << "销毁一个MyException异常对象,名称为:" <}

string GetName()
{
char tmp[20];
memset(tmp, 0, sizeof(tmp));
sprintf(tmp, "%s:%d", m_name.c_str(), number);
return tmp;
}

virtual string Test_Virtual_Func() { return "这是MyException类型的异常对象";}

protected:
string m_name;
int number;

static int count;
};
int MyException::count = 0;

void main()
{
try
{
try
{
// 抛出一个异常对象
throw MyException("ex_obj1");
}
// 异常对象按值传递
catch(MyException e)
{
cout<cout<<"下面重新抛出异常"<

// 异常对象重新被抛出
throw;
}
}
// 异常对象再次按值传递
catch(MyException e)
{
cout<}
}

  程序运行的结果是:
  构造一个MyException异常对象,名称为:ex_obj1:1
  拷贝一个MyException异常对象,名称为:ex_obj1:2
  拷贝一个MyException异常对象,名称为:ex_obj1:3
  销毁一个MyException异常对象,名称为:ex_obj1:1

  捕获到一个MyException*类型的异常,名称为:ex_obj1:3
  下面重新抛出异常

  拷贝一个MyException异常对象,名称为:ex_obj1:4
  销毁一个MyException异常对象,名称为:ex_obj1:3

  捕获到一个MyException*类型的异常,名称为:ex_obj1:4
  销毁一个MyException异常对象,名称为:ex_obj1:4
  销毁一个MyException异常对象,名称为:ex_obj1:2

  通过上面的程序运行结果,可以很明显地看出,异常对象在被重新抛出时,又有了一次拷贝复制的过程,瞧瞧!正常情况下,按值传递异常的方式应该是有3次构造对象的过程,可现在有了4次。那么这个异常对象在什么时候又再次被复制构造的呢?仔细分析一下,其实也不难明白, “异常对象ex_obj1:1”是局部变量;“异常对象ex_obj1:2”是临时变量;“异常对象ex_obj1:3”是第一个(内层的)catch block中的参数变量。当在catch block中再次throw异常对象时,它会即刻准备离开当前的catch block域,继续往上搜索对应的catch block模块,找到后,即完成异常对象的又一次复制构造过程,也即把异常对象传递给上一层的catch block域中。之后,正式离开内层的catch block域,并析构销毁这个catch block域中的异常对象ex_obj1:3,注意此时,属于临时变量形式的异常对象ex_obj1:2并没有被析构,而是直至到后一个catch block处理完后,先析构销毁异常对象ex_obj1:4,再才销毁异常对象ex_obj1:2。整个程序的执行流程如图14-1所示。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » 第14集再探C++中异常的rethrow

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情