Effective C++ 规则29:为“异常安全”而努力是值得的

       1. 带有异常安全的函数要求有两个条件:1)不泄露任何资源;2)不允许数据败坏;

       2. 异常安全函数提供以下三个保证:

            1)基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下,没有任何对象或数据结构会因此而败坏,所有对象都处于一种内部前后一致的状态。

             2)强烈保证:如果异常被抛出,程序状态不改变。换句话说,如果函数成功,就是完全成功,如果失败,程序会回到“调用函数之前”的状态。

             3)不抛掷保证:承诺绝不抛出异常,因为它们总是能够完成它们原先承诺的功能。

class PrettyMenu{ 
public: 
    ... 
    void changeBackground(std::istream& imgSrc); 
    ... 
private: 
    Mutex mutex; 
    Image* bgImage; 
    int imageChanges; 
}; 
 
void PrettyMenu::changeBackground(std::istream& imgSrc) 
{ 
    lock(&mutex); 
    delete bgImage; //删除旧的背景图片
    ++imageChanges; //修改图像变更次数
    bgImage = new Image(imgSrc); //安装新的背景图像
    unlock(&mutex); 
}

         对于changeBackground函数不满足异常安全函数的两个条件,但是可以通过使用智能指针和调整语句顺序(事件发生后再改变状态)解决出现异常时内存泄漏和数据不一致的问题。代码如下:

class PrettyMenu{ 
    ... 	
		std::tr1::shared_ptr<Image> bgImage; 
    ... 		
};
 
void PrettyMenu::changeBackground(std::istream& imgSrc) 
{ 
    Lock m1(&mutex);	
    bgImage.reset(new Image(imgSrc)); 
    ++imageChanges; 
}

        强烈保证有一个一般化的方法copy-and-swap,但是这个方法并非对所有函数都可实现或者具备意义,代码如下:

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);//置换数据 
}

        基本思想,为你打算修改的对象做一个副本,然后在副本身上做一切必要修改。若有任何修改动作抛出异常,原对象仍保持未改变状态,待所有改变成功后,再将修改过的那个副本和原对象在一个不跑出异常的操作中置换。

        这种方法会有副本的存在,时间上有损耗,具体要根据情况分析,而且并不是使用了这个方法就一定可以实现强烈保证,代码如下:

void somefunc()
{
    … //copy
    f1();
    f2();
    … //swap
}

        即使使用了copy-and-swap方法,如果在f1中对数据进行了修改,f2抛出异常,那么数据也是被修改过的,所以具体问题要具体分析,不能实现强烈保证,基本保证要实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值