C++箴言防止因异常而离开析构函数_第1页
C++箴言防止因异常而离开析构函数_第2页
C++箴言防止因异常而离开析构函数_第3页
C++箴言防止因异常而离开析构函数_第4页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C+箴言:防止因异常而离开析构函数C+ 并不禁止从析构函数中引发异常,但是这确实妨碍了实践。至于有什么好的理由,考虑: class Widget public:.Widget() . / assume this might emit an exception; void doSomething()std:vector<Widget> v;. / v is automatically destroyed here 当 vector v 被析构时,它有责任销毁它包含的所有 Widgets.假设 v 中有十个 Widgets,在销毁第一个的时候,抛出一个异常。其他 9个 Wid

2、gets 仍然必须被销毁(否则他们持有的任何资源将被泄漏),所以 v 应该调用它们的析构函数。但是假设在这个调用期间,第二个 Widgets 的析构函数又抛出一个异常。现在有两个异常同时在活动中,对于 C+ 来说这太多了。在非常巧合的条件下发生这样两个同时活动的异常,程序的执行会终止或者引发未定义行为。在本例中,将引发未定义行为。与此相同,使用任何标准库容器(比如,list,set),任何 TR1中的容器,甚至是一个数组,都可能会引发未定义问题。并非必须是容器或数组才会陷入麻烦。程序夭折或未定义行为是析构函数引发异常的结果,即使没有使用容器或数组也会如此。C+ 不喜欢引发异常的析构函数。 这比

3、较容易理解,但是如果你的析构函数需要执行一个可能失败而抛出异常的操作,该怎么办呢?例如,假设你与一个数据库连接类一起工作: class DBConnection public:.static DBConnection create(); / function to return/ DBConnection objects; params/ omitted for simplicity void close(); / close connection; throw an; / exception if closing fails 为了确保客户不会忘记调用 DBconnection 对象

4、的 close,一个合理的主意是为 DBConnection 建立一个资源管理类,在它的析构函数中调用 close.这样的资源管理类将在以后的文章中探讨,但在这里,只要认为这样一个类的析构函数看起来像这样就足够了: class DBConn / class to manage DBConnectionpublic: / objects.DBConn() / make sure database connections / are always closeddb.close();private:DBConnection db; 它允许客户像这样编程:  / open a bl

5、ockDBConn dbc(DBConnection:create(); / create DBConnection object/ and turn it over to a DBConn/ object to manage. / use the DBConnection object/ via the DBConn interface / at end of block, the DBConn/ object is destroyed, thus/ automatically calling close on/ the DBConnection object 既然能成功地调用 close

6、那就好了,但是如果这个调用导致了异常,DBConn 的析构函数将散播那个异常,也就是说,它将离开析构函数。这就产生了问题,因为析构函数抛出了一个烫手的山芋。有两个主要的方法避免这个麻烦。DBConn 的析构函数能:终止程序 如果 close 抛出异常,调用 abort。 DBConn:DBConn()try db.close(); catch (.) make log entry that the call to close failed;std:abort(); 如果程序在析构过程遭遇到错误后不能继续运行,这就是一个合理的选择。它有一个好处是:如果允许从析构函数散播异常可能会引起未

7、定义行为,这样就能防止它发生。也就是说,调用 abort 就预先防止了未定义行为。抑制这个异常 起因于调用 close: DBConn:DBConn()try db.close(); catch (.) make log entry that the call to close failed; 通常,抑制异常是一个不好的主意,因为它会隐瞒重要的信息某些事情失败了!可是,有些时候,抑制异常比冒程序夭折或未定义行为的风险更可取。程序必须能够在遭遇到错误并忽略之后还能继续可靠地执行,这才能成为一个可行的选择。这些方法都不太吸引人。它们的问题在于程序无法在第一现场对引起 close 抛出异常

8、的条件做出回应。一个更好的策略是设计 DBConn 的接口,以使它的客户有机会对可能会发生的问题做出回应。例如,DBConn 能够自己提供一个 close 函数,从而给客户一个机会去处理从那个操作中发出的异常。它还能保持对它的 DBConnection 是否已被关闭的跟踪,如果没有关闭就在析构函数中自己关闭它。这样可以防止连接被泄漏。如果在 DBConnection 的析构函数中调用 close 失败,无论如何,我们还可以再返回到终止或者抑制。class DBConn public:.void close() / new function for / client usedb.close();

9、closed = true;DBConn()if (!closed) try / close the connectiondb.close(); / if the client didntcatch (.) / if closing fails,make log entry that call to close failed; / note that and. / terminate or swallowprivate:DBConnection db;bool closed;    将调用 close 的责任从 DBConn 的析构函数转移到 DBConn 的客户

10、(同时在 DBConn 的析构函数中包含一个“候补”调用)可能会作为一种肆无忌惮地推卸责任的做法而刺激你。你甚至可以把它看作一个忠告(使接口易于正确使用)的违背。实际上,这都不正确。如果一个操作可能失败而抛出一个异常,而且可能是一个需要处理的异常,这个异常就必须来自非析构函数。这是因为析构函数引发异常是危险的,永远都要冒着程序夭折或未定义行为的风险。在此例中,让客户调用 close 并不是强加给他们的负担,而是给他们一个时机去应付错误,否则他们将没有机会做出回应。如果他们找不到可用到机会(或许因为他们相信不会有错误真的发生),他们可能忽略它,依靠 DBConn 的析构函数为他们调用 close。如果一个错误恰恰发生在那时如果由 close 抛出如果 DBConn 抑制了那个异常或者终止了程序,他们将无处诉苦。毕竟,他

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论