Effective C++:条款29:为“异常安全”而努力是值得的
(一)先看以下这些代码:
class PrettyMenu {
public:
void changeBackground(istream& imgSrc);
private:
Mutex mutex; //由于这个class希望用于多线程环境,所以它有这个相互排斥器作为并发控制之用
Image* bgImage; //眼下的背景图像
int imageChanges; //背景图像被改变的次数
};
void PrettyMenu::changeBackground(std::istream &imgSrc) {
lock(&mutex); //取得相互排斥器
delete bgImage; //摆脱旧的背景图像
++imageChanges; //改动图像变更次数
bgImage = new Image(imgSrc); //安装新的背景图像
unlock(&mutex); //释放相互排斥器
}
上面的函数不是“异常安全性”函数,由于“异常安全性”函数所需满足的两个条件。上面这个函数都不满足。
。
第一个条件:不泄露不论什么资源。
(上面这个函数当new Image(imgSrc)发生异常的话。unlock(&mutex)就永远不会被运行,所以就资源泄漏了)。
第二个条件:不同意数据败坏。(上面这个函数当new Image(imgSrc)发生异常的话,bgImage就是指向一个已删除的对象)。
(二)
(1)解决上面那个函数泄漏资源的问题的办法:用Lock class作为一种“确保相互排斥器被及时释放”的方法,以对象管理资源:
void PrettyMenu::changeBackground(std::istream &imgSrc) {
Lock m1(&mutex);
delete bgImage; //摆脱旧的背景图像
++imageChanges; //改动图像变更次数
bgImage = new Image(imgSrc); //安装新的背景图像
}
(2)解决上面那个函数数据败坏的办法:
首先,
异常安全函数提供下面三个保证之中的一个:
1. 基本承诺:假设异常被抛出,程序内的不论什么事物仍然保持在有效的状态下。
2. 强烈保证:假设异常被抛出,程序状态不改变。
3. 不抛掷保证:承诺绝不抛出异常,由于它们总是可以完毕它们原先承诺的功能。
又一次排列语句次序
class PrettyMenu {
...
std::tr1::shared_ptr<Image> bgImage;
...
};
void PrettyMenu::changeBackground(std::istream& imgSrc) {
Lock ml(&mutex);
bgImage.reset(new Image(imgSrc));
++imageChanges;
}
这两个改变差点儿足够让changeBackground提供强烈的异常安全保证。美中不足的是參数imgSrc。
假设Image构造函数抛出异常。有可能输入流的读取记号已被移走。而这种搬移对程序其余部分是一种可见的状态改变。
(三)
copy and swap的原则:为打算改动的对象做一个副本,在那个副本上做一切必要改动。若有不论什么改动动作抛出异常,源对象仍然保持未改变状态。待全部改变都成功后,再将改动过的副本和原对象在一个不抛出异常的swap中置换。
and swap方法下的pimpl idiom手段:
struct PMImpl {
std::tr1::shared_ptr<Image> bgImage;
int imageChanges;
};
class PrettyMenu {
private:
Mutex mutex;
std::tr1::shared_ptr<PMImpl> pImpl;
};
void PrettyMenu::changeBackground(std::istream& imgSrc) {
using std::swap;
Lock ml(&mutex);
std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl));
pNew->bgImage.reset(new Image(imgSrc)); //改动副本
++pNew->imageChanges;
swap(pImpl, pNew);//置换数据
}
请记住:
(1)异常安全函数(Exception-safe functions)即使发生异常也不会泄露资源或同意不论什么数据结构败坏。
这种函数区分为三种可能的保证:基本型、强烈型、不抛异常型。
(2)“强烈保证”往往可以以copy-and-swap实现出来,但“强烈保证”并不是对全部函数都可实现或具备现实意义。
(3)函数提供的“异常安全保证”通常最高仅仅等于其所调用的各个函数的“异常安全保证”中的最弱者。
Effective C++:条款29:为“异常安全”而努力是值得的的更多相关文章
- Effective C++ Item 29 为”异常安全”而努力是值得的
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:异常安全函数即使发生异常也不会泄漏资源或同意不论什么数据结构败坏.这种函数区分为三种 ...
- Effective C++ -----条款29:为“异常安全”而努力是值得的
异常安全函数(Exception-safe functions)即使发生异常也不会泄露资源或允许任何数据结构败坏.这样的函数区分为三种可能的保证:基本型.强烈型.不抛异常型. “强烈保证”往往能够以c ...
- 读书笔记 effective c++ Item 29 为异常安全的代码而努力
异常安全在某种意义上来说就像怀孕...但是稍微想一想.在没有求婚之前我们不能真正的讨论生殖问题. 假设我们有一个表示GUI菜单的类,这个GUI菜单有背景图片.这个类将被使用在多线程环境中,所以需要mu ...
- 条款29:为“异常安全”而努力是值得的
当异常被抛出时,带有异常安全性的函数: 1.不泄露任何资源 2.不允许数据败坏 异常安全函数提供以下三个保证之一: 1.基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效的状态下.没有任何对 ...
- [Effective C++ --029]为“异常安全”而努力是值得的
假设有个class用来表现夹带背景图案的GUI菜单单,这个class用于多线程环境,所以它有个互斥器(mutex)作为并发控制用: class PrettyMenu{ public: ... void ...
- 读书笔记_Effective_C++_条款二十九:为“异常安全”而努力是值得的
还是举书上的例子: void PrettyMenu::changeBackground(std::istream& imgSrc) { lock(&mutex); delete bgI ...
- Effective C++(Third Edition) Item29 为“异常安全”而努力是值得的
“异常安全”有两个条件: 1.不泄露任何资源 可以通过以对象管理资源的方式(Item13). 2.不允许数据败坏 异常安全函数提供以下三种保证之一 a.基本承诺 如果异常被抛出,程序内的任何事物都仍然 ...
- [More Effective C++]条款22有关返回值优化的验证结果
(这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回 ...
- More Effective C++ 条款0,1
More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类 ...
随机推荐
- Photon3Unity3D.dll 解析一
IPhotonPeerListener Photon客户端回调接口 1: //只要有来自Photon Server的事件就触发 2: public virtual void OnEvent( Eve ...
- 洛谷 P2708 硬币翻转 题解
题目传送门 真如题面所说,难度系数:☆☆☆☆☆(如果你看懂了). 从后往前扫一次,如果a[i]==0&&a[i-1]==1那么将ans+2. 注意最后不要忘记开头if(a[0]=='0 ...
- fastdfs5.11+centos7.2 按照部署(二)【转载】
https://files.cnblogs.com/files/xiaojf/nginx-1.12.0.tar.gz https://files.cnblogs.com/files/xiaojf/li ...
- SGU 209. Areas
209. Areas time limit per test: 0.25 sec.memory limit per test: 65536 KB input: standardoutput: stan ...
- 解决 VUE 微信 IOS 路由跳转问题
watch: { "$route"(){ if (/iPhone|mac|iPod|iPad/i.test(navigator.userAgent)) { location.hre ...
- jquery通配符说明
按姓名匹配 1,name前缀为aa的所有div的jquery对象 Js代码 收藏代码$("div[name^='aa']"); 2,name后缀为aa的所有div的jquery对象 ...
- JQuery经典总结
1.jQuery介绍 jQuery是一个js框架(其实就是一个.js文件),它的特点是使用选择器查找要操作的节点,并且将这些节点封装成一个jQuery对象.封装的目的是为了更好地兼容不同的浏览器之间的 ...
- 深度学习笔记之【随机梯度下降(SGD)】
随机梯度下降 几乎所有的深度学习算法都用到了一个非常重要的算法:随机梯度下降(stochastic gradient descent,SGD) 随机梯度下降是梯度下降算法的一个扩展 机器学习中一个反复 ...
- Java_关键字、匿名对象、内部类、访问修饰符、代码块
final关键字 概述: 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子类继承了这些特殊类之后, ...
- Linux中用户与组相关配置文件(整理)
用户与组信息存放位置 说明 注释 /etc/passwd 存放用户基本信息 记录了每个用户的一些基本属性,并对所有用户可读,每一行记录对应一个用户,属性之间通过冒号分隔. 每一个行6个冒号,7个属性. ...