“异常安全”应该满足两个条件——157
我们来定义一个变现夹带背景图案的GUI菜单类:
class PrettyMenu{
public:
...
void chageBackground(std::istream& imgSrc); //改变背景图案
...
private:
Mutex mutex; //互斥器
Image* bgImage; //目前的背景图案
int imageChanges; //背景图案被改变的次数
};
下面是PrettyMenu的changeBackground函数的一个可能实现:
void PrettyMenu::changeBackground(std::istream& imgSrc)
{
lock(&mutex);
delete bgImage;
++imageChanges;
bgImage=new Image(imgSrc);
unlock(&mutex);
}
这个函数没有满足当异常被抛出时,应该满足的条件:
(1)不泄露任何资源。上述代码一旦“new Image(imgSrc)”导致异常,对unlock的调用就绝不会执行。
(2)不允许数据败坏。如果“new Image(imgSrc)”抛出异常,bgImage就是指向一个已被删除的对象,imageChanges也已被累加,而其实并没有新的图像被成功安装起来。
解决资源泄漏——158
条款13讨论如何以对象管理资源,而条款14也导入了Lock class作为一种“确保互斥器被及时释放”的方法:
void PrettyMenu::changeBackground(std::istream& imgSrc)
{
lock ml(&mutex); //来自条款14
delete bgImage;
++imageChanges;
bgImage=new Image(imgSrc);
}
解决数据败坏——158
异常安全函数提供一下三个保证之一:
(1)基本承诺。
(2)强烈保证。
(3)不抛掷保证。
试着改下上节的changeBackground函数:
class PrettyMenu{
...
std::tr1::shared_ptr<Image> bgImage; //改动1:使用智能指针
...
};
void PrettyMenu::changeBackground(std::istream& imgSrc)
{
Lock ml(&mutex);
bgImage.reset(new Image(imgSrc));
++imageChanges; //改动2:重排语句次序
}
结论——164
(1)异常安全函数即使发生异常也不会泄漏资源或允许任何数据结构败坏。这样的函数区分为三种可能的保证:基本型、强烈型、不抛异常型。
(2)“强烈保证”往往能够以copy-and-swap实现出来,但“强烈保证”并非对所有函数都可实现或具备现实意义。
(3)函数提供的“异常安全保证”通常最高只等于其所调用的各个函数的“异常安全保证”中的最弱者。
本文探讨了异常安全的编程原则,通过分析一个GUI菜单类的案例,解释了如何避免资源泄漏和数据败坏,提出了使用智能指针和copy-and-swap技术的解决方案,并详细讨论了不同级别的异常安全保证。
768

被折叠的 条评论
为什么被折叠?



