异常安全

异常安全的代码需要满足两个条件:

  1. 异常中立性
  2. 异常安全性

异常中立性是指任何底层的异常都能保持原样传递到外层调用代码。

而异常安全性也有两个条件:

  1. 不泄露任何资源
  2. 不允许数据破坏

只有满足上诉两个条件的函数才称为拥有异常安全性。

这里主要讨论异常安全性的保证。

不泄露任何资源

解决资源泄露的问题比较容易,可以通过智能指针等对象管理资源来确保资源被正确释放。

不允许数据被破坏

  • 基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下。没有任何对象或数据机构会因此而被破坏,所有对象都处于一种内部前后一致的状态。

  • 强烈保证:如果异常被抛出,程序状态不改变。调用这样的函数需要有这样的认知:如果函数成功,就是完全成功;如果函数失败,程序会回到“调用函数之前”的状态。

  • 不抛出保证:保证绝对不抛出异常。对于所有对内建类型(例如,ints,指针,等等)的操作都是不抛出(nothrow)的(也就是说,提供不抛出保证)。这是异常安全代码中必不可少的基础构件。

一个异常安全的函数必须保证满足上诉三个条件之一。如果不这样,那么就不具备异常安全性。

实现数据不被破坏

我们在写代码时,保证满足其中一个条件。从异常安全的角度来说,nothrow 是最优的选择,但是实际上很难不调用任何一个可能抛出异常的函数。所以大多数时候会选择 基本保证强烈保证 之一。

实现 强烈保证 的一种策略是使用 copy and swap 技术:

为你打算修改的对象做一份备份,然后在副本上做一切必要的修改。若有任何修改动作抛出异常,原对象仍保持未改变状态。待所有改变都成功后,再将修改过的副本和原对象在一个不抛出异常的操作中做置换。

需要注意的是函数提供的“异常安全保证”通常只等于其所调用的各函数的“异常安全保证”中的最弱的一项。