如果异常类的构造函数抛出异常,会发生什么?

如果异常类的构造函数抛出异常,会发生什么?

1. 如果异常类的复制构造函数抛出异常,则程序会中止(abort)。
上述结论是肯定成立的,但是对此还有很多实际情况需要区分对待,如下所述。

首先:
class foo{
public:
 foo() {}
 foo(const foo&){
  throw 1;
 }
};
int main(int argc, char **argv){
 try{
  foo f;
  throw f;
 }
 catch(...){
  cout << "Ok, reach here" << endl;
 }
 return 0;
}
在GCC3.4.2上运行程序,结果:
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
这表明,在throw f的同时,对异常对象f进行拷贝时抛出了异常,程序被非正常中止了。
(但是,在vs2005上的实验结果是:正常显示“Ok, reach here”,并没有中止程序:(,不解其缘由)


对上述程序稍作修改,如下:
class foo{
public:
 foo() {}
 foo(const foo&){
  throw 1;
 }
};
int main(int argc, char **argv){
 try{
  throw foo();//此处抛出一个临时对象,而非命名对象
 }
 catch(...){
  cout << "Ok, reach here" << endl;
 }
 return 0;
}
在GCC3.4.2上运行程序,结果:
Ok, reach here
此处程序并没有被非正常中止,因为throw foo()抛出的是一个临时对象,理论上的过程是这样的:“先调用foo()构造一个临时对象,然后将此临时对象复制一份作为抛出的异常进行传播”,但是编译器对此过程作了优化,将拷贝的过程优化掉了(比如直接将这个临时对象进行传播,或者直接在要抛出的异常对象中进行foo()的调用对其初始化进而而不产生临时对象,等等),所以在throw foo()的时候没有拷贝的行为发生。此外,这个程序特殊的地方还在于,不仅在产生异常处(即throw处)没有拷贝行为,而且在异常的接收端(即catch处)也同样没有拷贝行为,因为catch(...)表示接收任何异常,用户无法在catch中引用到这个被捕获的异常,所以没有拷贝行为(注:如果按引用捕获异常catch(foo &f),也同样没有拷贝行为)。
(在vs2005上的实验结果也是:正常显示“Ok, reach here”,与GCC相同)


对程序再作修改,如下:
class foo{
public:
 foo() {}
 foo(const foo&){
  throw 1;
 }
};
int main(int argc, char **argv){
 try{
  throw foo();
 }
 catch(foo){ //此处发生了改变
  cout << "Ok, reach here" << endl;
 }
 return 0;
}
在GCC3.4.2上运行程序,结果:
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
这表明在异常捕获端(即catch(foo)处)发生了拷贝行为(尽管在异常抛出处(即throw处)没有发生拷贝行为,如上面所述),所以程序非正常中止。
(但是,在vs2005上的实验结果是:正常显示“Ok, reach here”,并没有中止程序。如果将catch(foo)改成catch(foo f),则结果就与GCC相同了(程序非正常中止)。这是因为vs看到catch(foo)并没有给出异常的名称,因此在catch中仍然无法引用到这个被捕获的异常,所以就没有进行拷贝。可是我认为这种做法不太妥当,应该是一种“不成熟的优化”,因为它没有考虑到copy constructor有副作用的情况,即如果copy constructor除了拷贝之外还担负着其他的责任(当然,这不符合“单一职责原则”,但现实中确实可能存在),那vs的这种优化就会让程序的行为出乎编程者的意料。)


2. 如果异常类的其他构造函数抛出异常,则在此异常被抛出之前(也就是说,此异常并没有被抛出)另外一个异常就产生了,所以程序并不会中止,而是按照正常的方法去捕获并处理这个被抛出的异常。

例子:
class foo{
public:
 foo(){
  throw 1;
 }
 foo(const foo&){}
};
int main(int argc, char **argv){
 try{
  throw foo();
 }
 catch(...){
  cout << "Ok, reach here" << endl;
 }
 return 0;
}
在GCC3.4.2上运行程序,结果:
Ok, reach here
我们可以这样想这个程序:
int main(int argc, char **argv){
 try{
  foo temp;
  throw temp;
 }
 catch(...){
  cout << "Ok, reach here" << endl;
 }
 return 0;
}
因此,在“foo temp;”处就已经抛出异常了,所以根本就没有执行到throw,因此这个foo类型的异常根本就没有被抛出过,而catch(...)捕获到的异常是int型的1(foo的default constructor中throw 1的结果)。
(在vs2005上的实验结果也是:显示“Ok, reach here”,与GCC相同)

 

 

 

 


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值