effective c++ 关于异常安全

假设有个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);
}



猜你喜欢

转载自blog.csdn.net/duangyhn/article/details/78429134
今日推荐