Username: Password:

More Effective C++:通过引用捕获异常
来源:作者: 发布时间:2007-11-09 05:14:02

当您写一个catch子句时,必须确定让异常通过何种方式传递到catch子句里。您能够有三个选择:和您给函数传递参数相同,通过指针(by pointer),通过传值(by value)或通过引用(by reference)。

  我们首先讨论通过指针方式捕获异常(catch by pointer)。从throw处传递一个异常到catch子句是个缓慢的过程,在理论上这种方法的实现对于这个过程来说是效率最高的。因为在传递异常信息时,只有采用通过指针抛出异常的方法才能够做到不拷贝对象,例如:

class exception { ... }; // 来自标准C++库(STL)
 // 中的异常类层次
 void someFunction()
 {
  static exception ex; // 异常对象
  ...
  throw &ex; // 抛出一个指针,指向ex
  ...
 }
 void doSomething()
 {
  try {
   someFunction(); // 抛出一个 exception*
  }
  catch (exception *ex) { // 捕获 exception*;
   ... // 没有对象被拷贝
  }
 }



  这看上去很不错,但是实际情况却不是这样。为了能让程式正常运行,程式员定义异常对象时必须确保当程式控制权离开抛出指针的函数后,对象还能够继续生存。全局和静态对象都能够做到这一点,但是程式员很容易忘记这个约束。假如真是如此的话,他们会这样写代码:

void someFunction()
{
 exception ex; // 局部异常对象;
 // 当退出函数的生存空间时
 // 这个对象将被释放。
 ...
 throw &ex; // 抛出一个指针,指向
 ... // 已被释放的对象
}

  这简直糟糕透了,因为处理这个异常的catch子句接受到的指针,其指向的对象已不再存在。

  另一种抛出指针的方法是在建立一个堆对象(new heap object):
void someFunction()
{
 ...
 throw new exception; // 抛出一个指针,指向一个在堆中
 ... // 建立的对象(希望
}
// 自己不要再抛出一个
// 异常!)


  这避免了捕获一个指向已被释放对象的指针的问题,但是catch子句的作者又面临一个令人头疼的问题:他们是否应该删除他们接受的指针?假如是在堆中建立的异常对象,那他们必须删除他,否则会造成资源泄漏。假如不是在堆中建立的异常对象,他们绝对不能删除他,否则程式的行为将不可预测。该怎样做呢?

  这是不可能知道的。一些clients可能会传递全局或静态对象的地址,另一些可能转递堆中建立的异常对象的地址。通过指针捕获异常,将碰到一个哈姆雷特式的难题:是删除还是不删除?这是个难以回答的问题。所以您最好避开他。

  而且,通过指针捕获异常也不符合C++语言本身的规范。四个标准的异常——bad_alloc(当operator new(参见条款8)不能分配足够的内存时,被抛出),bad_cast(当dynamic_cast针对一个引用(reference)操作失败时,被抛出),bad_typeid(当dynamic_cast对空指针进行操作时,被抛出)和bad_exception(用于unexpected异常; 参见条款14)——都不是指向对象的指针,所以您必须通过值或引用来捕获他们。

[1][2]

喜欢本文,那就收藏到:

    Del.icio.us Google书签 Digg Live Bookmark Technorati Furl Yahoo书签 Facebook 百度搜藏 新浪ViVi 365Key网摘 天极网摘 和讯网摘 博拉网 POCO网摘 添加到饭否 QQ书签 Digbuzz我挖网
相关评论  我也要评论
还没有关于此文章的相关评论!
  • 昵称: (为空则显示guest)
  • 评论分数: ★ ★ ★★★ ★★★★ ★★★★★
  • 评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
  • 导航
    赞助商
    文章类别
    订阅