《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会进行补充说明;

posted @ 2020-12-04 13:04  暮云林凌  阅读(135)  评论(0)    收藏  举报