effective c++ 关于异常安全

来源:互联网 发布:java并发log 编辑:程序博客网 时间:2024/06/06 16:40

假设有个class用来表现夹带背景图案的GUI菜单,用于多线程,有个互斥器作为并发控制

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也已被累加,其实新图像没被成功安装。

 

解决资源泄露很容易:

void PrettyMenu::changeBackground(std::istream& imgSrc){Lock m1(&mutex);delete bgImage;++imageChanges;bgImage=new Image(imgSrc);}


关于数据败坏

异常安全函数提供三个保证之一:

1)基本承诺:如果异常抛出,程序内任何事物保持在有效状态

2)强烈保证:如果异常抛出,程序状态不变

3)不抛出异常

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

这两个改变几乎足够让changeBackground提供强烈的异常安全保证。如果Image构造函数抛出异常,有可能输入流读取记号已被移走,这样的搬移对程序其余部分是可见的状态改变。

 

copy and swap

将隶属对象的数据从源对象放进另一个对象,然后赋予源对象一个指针,指向所谓的实现对象,典型写法如下:

struct PMImple{std::shared_ptr<Image>bgImage;int imageChange;};class PrettyMenu{...private:Mutex mutex;std::shared_ptr<PMImple>pImple;};void PrettyMenu::changeBackground(std::istream& imgSrc){using std::swap;Lock m1(&mutex);std::shared_ptr<PMImple>pnew(new PMImple(*pImple));pnew->bgImage.reset(new Image(imgSrc));++pNew->imageChanges;swap(pImple,pnew);}



阅读全文
0 0