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

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);

}

异常安全有两个条件:

1.不泄露任何资源。上述代码一旦“new Image(imgSrc)"导致异常,对unlock的调用就绝不会执行,于是互斥器就永远呗把持住了。

2.不允许数据败坏。如果“new Image(ImgSrc)"抛出异常,bgImage就是指向一个已被删除的对象,imageChanges已被累加,而其实没有新的图像被成功安装起来。

解决资源泄漏的问题很简单:

因为条款13讨论过如何以对象管理资源,而条款14也导入Lock class作为一种“确保互斥器被及时释放”的方法:

void PrettyMenu::changeBackground(std::istream& imgSrc)

{
     Lock ml(&mutex);

     delete bgImage;

      ++imageChanges;

     bgImage = new Image(imgSrc);

}

我们现在专注解决数据的败坏了。

1.首先改变PrettMenu的bgImage成员变量的类型,从一个类型为Image* 的内置指针改为一个“用于资源管理”的智能指针。

以对象(例如智能指针)管理资源是良好设计的根本。

2.重新排列chageBackground内的语句次序,使得在更换图像之后才累加 Image Changes.

class PrettyMenu

{
      ...

       std::tr1::shared_ptr<Image> bgImage;

         ...

};

void PrettyMenu::chageBackground(std::istream & imgSrc)

{
     Lock ml(&mutex);

    bgImage.reset(new Image(imgSrc));

++imageChanges;

}

注意,这里不再需要的手动delete旧图像,因为这个动作已经由智能指针内部处理掉了。此外,删除动作只发生在新图像被成功创建后。更正确地说,tr1::shared_ptr::reset函数只有在其参数(也就是“new Image(imgsrc)"的执行结果)被成功生成之后才会被调用。delete只在reset函数内被使用,所以如果从未进入那个函数也就绝不会使用delete。

-------------------------------------------------------------------------------------------------------------------------------------

有一个一般化的设计策略被称为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);

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值