C++实现之——异常安全性保证

定义类PrettyMenu如下:

 1 class PrettyMenu
 2 {
 3 public:
 4        ...
 5        void changeBackground(istream& imgSrc);
 6        ...
 7 private:
 8        Mutex mutex;
 9        Image* bgImage;
10        int imageChanges;
11 };
View Code

成员函数changeBackground的实现如下:

1 void PrettyMenu::changeBackground(std::istream& imgSrc)
2 {
3      lock(&mutex);
4      delete bgImage;
5      ++ imageChanges;
6      bgImage = new Image(imgSrc);
7      unlock(&mutex);
8 }

上面的代码逻辑上是很合理的,但是如果new Image(imgSrc)的执行导致异常,那么就有可能出现两个问题:
1)mutex资源被泄漏,将被永远锁住;

2)imageChanges改变了,bgImage指向一个已删除的对象,即所谓的数据败坏了。

上面的两个问题都是异常安全性所不能存在的问题。对于资源泄漏,可以通过使用对象管理资源进行解决;而对于数据败坏, 也可以资源管理类实现,如下:

 1 class PrettyMenu
 2 {
 3 ...
 4 std::tr1::shared_ptr<Image> bgImage;
 5 ...
 6 };
 7 
 8 void PrettyMenu::changeBackground(std::istream& imgSrc)
 9 {
10 Lock ml(&mutex);
11 bgImage.reset(new Image(imgSrc));
12 
13 ++ imageChanges;
14 }
View Code

这时delete语句写在了reset函数中,如果new Image有异常,那么就进不到函数reset中,最终delete语句就不会执行。

在保证要被修改的对象要么不变要么全变的一个典型策略是copy and sawp,即首先复制要改变对象的一个副本,将所有的修改都多用于该副本,修改成功之后交换两者的指针,就实现了原对象的修改,否则原对象保持不变。

 

通常,一个函数的最高“异常安全性保证”等价于其所调用函数中最低的那个“异常安全性保证”。

以上整理自Effective C++中文版第三版 case 29.

 

posted on 2013-06-03 20:43  Sophia-呵呵小猪  阅读(355)  评论(0编辑  收藏  举报