NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
## 条款29:为”异常安全“而努力是值得的 Strive for exception-safe code. ### 异常安全的两个条件 ```cpp void PrettyMenu::changeBackground(std::istream& imgSrc) { lock(&mutex); delete bgImage; ++imageChanges; bgImage = new Image(imgSrc); unlock(&mutex); } ``` 异常安全有两个条件: * 不泄露任何资源:当 `new Image(imgSrc)` 导致异常,`unlock` 则绝的不会被执行,导致了锁资源的泄漏; * 不允许数据败坏:当 `new Image(imgSrc)` 导致异常,`bgImage` 就是指向一个已被删除的对象,并且 `imageChanges` 也被累加; 而 C++ 提供一些机制来保证异常安全: ```cpp class PrettyMenu { ... std::tr2::shared_ptr<Image> bgImage; ... }; void PrettyMenu::changeBackground(std::istream& imgSrc) { Lock m1(&mutex); // 使用资源管理类管理锁 bgImage.reset(new Image(imgSrc); // 智能指针 ++imageChanges; } ``` ### 异常安全的三个保证等级 异常安全函数(Exception-safe functions)提供以下三个保证之一: * 基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态; * 强烈保证:如果异常被抛出,程序状态不变,即函数成功就是完全成功,函数失败程序就会回复到”调用函数之前的状态“; * 不抛掷(nothrow)保证:承诺绝对不抛出异常,因为它们总是能够完成它们原先承诺的功能; ### copy and swap 在修改一个对象时,可以先创建一个副本,然后在副本身上做一切必要的修改;若有任何修改动作抛出异常,原对象仍保持未改变的状态;待所有改变成功后,再将修改过的那个副本和原对象在一个不抛出异常的操作中置换。 ”copy and swap“ 策略是对对象状态做出”全有或全无“改变的一个很好的办法,但一般而言它并不保证整个函数有强烈的异常安全性。 "copy and swap" 策略有两个需要注意的方面: * ”连带影响“(side effect),如果函数值操作局部性状态(local state),便相对容易地提供强烈保证;但如果函数对”非局部性数据“(non-local data)有连带影响时,提供强烈保证就很困难; * 效率,创建副本和交换操作将带来时间和空间的开销;