失败后保留什么
一个操作可能已经修改对象,才在后续步骤抛出异常。异常安全关注的不是能否写出捕获语句,而是控制权离开时,对象不变量、已取得资源以及调用者可以继续做的操作是否仍有明确约定。
基本保证允许状态发生变化,但要求保留不变量且不泄漏相关资源;强保证进一步要求失败时受保护状态保持原样。不抛出保证则要求异常不向调用者传播。它们必须落实到具体操作,不能仅凭一个类使用了异常就推断其保证。
先保护资源,再组织提交
资源句柄可以让已经取得的内存、文件等在异常展开时自动清理,减少分支中遗漏释放的机会。但自动清理并不必然撤销已经写入的对象状态,基本保证与强保证仍需分别设计。
一种取得强保证的办法是先在临时副本上完成可能失败的工作,成功后再用不会失败的提交操作替换原状态。Abrahams的示例也指出,这可能增加复制成本;若提交或回滚本身还会抛出,原来的推理就不能成立。
组件的保证需要组合核对
泛型容器还依赖元素类型、分配器和其他操作的行为。复制、交换或析构的异常约定发生变化,可能影响外层能承诺的保证;不能把某个示例中交换不抛出的前提套用到所有类型。
声明不抛出也不能替代错误处理设计。C++的noexcept规定异常不得逃出该边界,违反时会终止程序;是否能成功完成业务操作,还取决于函数采取的错误报告方式和自身前提。