《Effective C++》条款11:对于operator=中“自我赋值”的处理
对于自我赋值,第一反应是形如x=x的形式,这只是最常见的一种而已;
对于自我赋值,往往存在都比较隐式:例如指向同一对象的指针或者引用进行赋值,也算是自我赋值的一种;
比较直观的是在派生和继承中的指向问题;
例如:两个不同的指针分别指向基类base和派生类derived,但是由于base指针任然可以指向派生类,所以无法断定两个指针是否都指向同一个derived类,有可能会造成自我赋值的问题;
所以本次议题目标:确定任何函数如果操作一个以上的对象时,如果多个对象是同一个对象时,其行为仍然正确;
同理,自我赋值也存在某种缺陷,例如比较典型的空间释放问题:
class Bitmap{
public:
Bitmap(const Bitmap& Bm);
};
class widget {
public:
widget& operator=(const widget& rhs);
private:
Bitmap* pb;
};
widget& widget::operator=(const widget& rhs) {
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
上述的问题主要存在于自我赋值情况下,this和rhs指向同一个类,如果采用delete pb,则会使得rhs也释放pb,从而导致赋值为空指针,和预期情况并不符;
针对于上述自我赋值可能出现的问题,书中大致阐述了几种解决方式:
1.进行认同测试;
2.利用新版本的“异常安全性”防止自我赋值出现问题;
3.利用copy and swap技术进行;
认同测试:
即在进行赋值前进行是否是同一对象的自检测;
widget& widget::operator=(const widget& rhs) {
if (this == &rhs)
return *this;
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
如果是同一对象,直接返回,如果不是同一对象,进行赋值;
新版本“异常安全性”:
新版本异常安全性主要是针对于new时空间不足分配失败;
当new失败后,pb不会改变,仍然只想原来的对象,不再像之前的operator=版本那样指向为空;
所以只需要在相应位置进行异常捕捉即可;
widget& widget::operator=(const widget& rhs) {
Bitmap* pOrig = pb;
pb = new Bitmap(*rhs.pb);
delete pOrig;
return *this;
}
其中pOrig保存了初始的对象;
copy and swap技术:
后续条款29会进行补充说明;

浙公网安备 33010602011771号