Effective C++: Exception-safe code
异常安全
异常安全的代码需要满足两个条件:
- 异常中立性
- 异常安全性
异常中立性是指任何底层的异常都能保持原样传递到外层调用代码。
而异常安全性也有两个条件:
- 不泄露任何资源
- 不允许数据破坏
只有满足上诉两个条件的函数才称为拥有异常安全性。
这里主要讨论异常安全性的保证。
不泄露任何资源
解决资源泄露的问题比较容易,可以通过智能指针等对象管理资源来确保资源被正确释放。
不允许数据被破坏
-
基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下。没有任何对象或数据机构会因此而被破坏,所有对象都处于一种内部前后一致的状态。
-
强烈保证:如果异常被抛出,程序状态不改变。调用这样的函数需要有这样的认知:如果函数成功,就是完全成功;如果函数失败,程序会回到“调用函数之前”的状态。
-
不抛出保证:保证绝对不抛出异常。对于所有对内建类型(例如,ints,指针,等等)的操作都是不抛出(nothrow)的(也就是说,提供不抛出保证)。这是异常安全代码中必不可少的基础构件。
一个异常安全的函数必须保证满足上诉三个条件之一。如果不这样,那么就不具备异常安全性。
实现数据不被破坏
我们在写代码时,保证满足其中一个条件。从异常安全的角度来说,nothrow 是最优的选择,但是实际上很难不调用任何一个可能抛出异常的函数。所以大多数时候会选择 基本保证 和 强烈保证 之一。
实现 强烈保证 的一种策略是使用 copy and swap 技术:
为你打算修改的对象做一份备份,然后在副本上做一切必要的修改。若有任何修改动作抛出异常,原对象仍保持未改变状态。待所有改变都成功后,再将修改过的副本和原对象在一个不抛出异常的操作中做置换。
需要注意的是函数提供的“异常安全保证”通常只等于其所调用的各函数的“异常安全保证”中的最弱的一项。