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

本文探讨了异常安全的编程原则,通过分析一个GUI菜单类的案例,解释了如何避免资源泄漏和数据败坏,提出了使用智能指针和copy-and-swap技术的解决方案,并详细讨论了不同级别的异常安全保证。

“异常安全”应该满足两个条件——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)函数提供的“异常安全保证”通常最高只等于其所调用的各个函数的“异常安全保证”中的最弱者。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值