(一)先看以下这些代码:

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.  不抛掷保证:承诺绝不抛出异常,由于它们总是可以完毕它们原先承诺的功能。

对changeBackground而言,首先。从一个类型为Image*的内置指针改为一个“用于资源管理”的智能指针。第二,又一次排列changeBackground内的语句次序。使得在更换图像之后再累加imageChanges。

又一次排列语句次序

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中置换。

实际上一般是将全部“隶属对象的数据”从原对象放进还有一个对象内,然后赋予原对象一个指针,指向那个所谓的实现对象(即副本)。
实现例如以下:使用copy
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:为“异常安全”而努力是值得的的更多相关文章

  1. Effective C++ Item 29 为”异常安全”而努力是值得的

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:异常安全函数即使发生异常也不会泄漏资源或同意不论什么数据结构败坏.这种函数区分为三种 ...

  2. Effective C++ -----条款29:为“异常安全”而努力是值得的

    异常安全函数(Exception-safe functions)即使发生异常也不会泄露资源或允许任何数据结构败坏.这样的函数区分为三种可能的保证:基本型.强烈型.不抛异常型. “强烈保证”往往能够以c ...

  3. 读书笔记 effective c++ Item 29 为异常安全的代码而努力

    异常安全在某种意义上来说就像怀孕...但是稍微想一想.在没有求婚之前我们不能真正的讨论生殖问题. 假设我们有一个表示GUI菜单的类,这个GUI菜单有背景图片.这个类将被使用在多线程环境中,所以需要mu ...

  4. 条款29:为“异常安全”而努力是值得的

    当异常被抛出时,带有异常安全性的函数: 1.不泄露任何资源 2.不允许数据败坏   异常安全函数提供以下三个保证之一: 1.基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效的状态下.没有任何对 ...

  5. [Effective C++ --029]为“异常安全”而努力是值得的

    假设有个class用来表现夹带背景图案的GUI菜单单,这个class用于多线程环境,所以它有个互斥器(mutex)作为并发控制用: class PrettyMenu{ public: ... void ...

  6. 读书笔记_Effective_C++_条款二十九:为“异常安全”而努力是值得的

    还是举书上的例子: void PrettyMenu::changeBackground(std::istream& imgSrc) { lock(&mutex); delete bgI ...

  7. Effective C++(Third Edition) Item29 为“异常安全”而努力是值得的

    “异常安全”有两个条件: 1.不泄露任何资源 可以通过以对象管理资源的方式(Item13). 2.不允许数据败坏 异常安全函数提供以下三种保证之一 a.基本承诺 如果异常被抛出,程序内的任何事物都仍然 ...

  8. [More Effective C++]条款22有关返回值优化的验证结果

    (这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回 ...

  9. More Effective C++ 条款0,1

    More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类 ...

随机推荐

  1. java关键字(详解)

    目录 1. 基本类型 1) boolean 布尔型 2) byte 字节型 3) char 字符型 4) double 双精度 5) float 浮点 6) int 整型 7) long 长整型 8) ...

  2. Codeforces 918C The Monster(括号匹配+思维)

    题目链接:http://codeforces.com/contest/918/problem/C 题目大意:给你一串字符串,其中有'('.')'.'?'三种字符'?'可以当成'('或者')'来用,问该 ...

  3. 修改 jupyter notebook 启动工作路径的方法

    Windows下jupyter notebook默认的启动路径就是当前cmd启动jupyter 的路径: C:\Users\用户名>jupyter notebook 此时jupyter 的启动工 ...

  4. 【PAT】1004. 成绩排名 (20)

    1004. 成绩排名 (20) 读入n名学生的姓名.学号.成绩,分别输出成绩最高和成绩最低学生的姓名和学号. 输入格式:每个测试输入包含1个测试用例,格式为 第1行:正整数n 第2行:第1个学生的姓名 ...

  5. scrapy 学习笔记1

    最近一段时间开始研究爬虫,后续陆续更新学习笔记 爬虫,说白了就是获取一个网页的html页面,然后从里面获取你想要的东西,复杂一点的还有: 反爬技术(人家网页不让你爬,爬虫对服务器负载很大) 爬虫框架( ...

  6. node+express+socket.io+mysql=通讯服务器搭建(一)

    首发github/blog 欢迎大家评论给星 安装 首先假定你已经安装了 Node.js,接下来为你的应用创建一个目录,然后安装express-generator应用骨架 $ mkdir node-d ...

  7. 快速搭建sonar代码质量管理平台

    安装 下载,直接解压http://www.sonarqube.org/downloads/ 添加mysql驱动至\extensions\jdbc-driver\mysql\ 创建mysql数据库和用户 ...

  8. shell-sed命令详解(转)

    (转自http://blog.csdn.net/wl_fln/article/details/7281986) Sed简介 sed是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时 ...

  9. HTTP协议的重新学习

    思论:做互联网一年多了,想了想对http协议的认识还处于很笼统的阶段,抽休息时间,重新梳理一下自己的网络知识. 1.什么叫HTTP协议? HTTP协议是Hyper TEXT Transfer Prot ...

  10. linux网络管理----网络基础

    1.1 ISO/OSI 七层模型 笔记: 打入ipconfig: mac地址:Media Access Control 也是物理地址,这是由网卡决定的.负责的是内网,也就是局域网通信. IPv4地址: ...