读书笔记:Effective C++ 炒冷饭 - Item 29 编写对异常免疫的代码

读书笔记:Effective C++ 炒冷饭 - Item 29 编写对异常免疫的代码
原创文章欢迎转载,但请保留作者信息]
Justin 于 2010-01-03

这里我所说的“对异常免疫的代码”,原文是exception-safe code。(侯捷的版本是“异常安全代码”,不过我觉得自己的版本比较容易理解……)

对异常免疫的函数在异常发生的时候应该具备两个特征:
  • 不泄漏任何资源(内存、锁等等)
  • 不造成任何数据结构的损坏
并能够提供至少以下保证中的一项:
  • 基本的保证:当异常抛出时,程序中的对象、数据免遭破坏。
  • 较强的保证:当异常抛出时,程序的状态不会被改变。
    从状态机的角度来看,若成功调用函数,则系统进入成功后的状态;如果函数中因异常而出错,系统应该留在调用函数前的状态:也就是说,系统在调用函数后,只会有两种状态。这是比前一条更强的保证。(看来Scott也爱上了比喻:书中说这就好比女生怀孕,要么就是怀上了,要么就是没中招,没人能“半”怀孕的@#¥%)
  • 最强的保证:不会有异常抛出。例如对内置类型的操作就不会抛出异常。这是最理想的,但也很难做到。更多的函数只能在前两者中做一选择。
为了能够提供较强的保证,也即系统的状态不因异常抛出与否而变化,大师又重新提出了“先拷贝后交换”(copy-and-swap)这一方法论来。
用不那么严谨的说法:为了避免在操作对象时触发异常影响系统状态,“先拷贝后交换”先是创建了一个临时对象,将所有的操作都施加在该临时对象上。如果没有出错,把这个处理过的临时对象和真正需要处理的对象交换一通,算是顺利完成任务;如果有错并抛出了异常,原系统状态也不会被影响,因为真正需要处理的对象根本没有被动过。
当然,天下没有免费的午餐。
“先拷贝后交换”不仅耗费了一个临时对象的存储代价,同时支出的还有后面交换对象时的时间和资源开销。因此,对异常免疫的较强保证是很好很强大,但是实际中并不是任何时候都需要做到那么高的保证。杀鸡岂需用牛刀?

最后要提醒的是,对异常免疫的函数也符合“短板理论”:木桶能装的水与其最短的那块木板有关,函数对异常免疫的程度也由函数中程度最低的代码(包括其调用的函数)决定。某个函数如果调用了另外一个一出现异常就崩溃的函数,那么这个函数就不能提供基本的异常免疫保证。

你可能感兴趣的:(读书笔记:Effective C++ 炒冷饭 - Item 29 编写对异常免疫的代码)