Effective C++ 条款11,12 在operator= 中处理“自我赋值” || 复制对象时不要忘记每一个成分
1、潜在的自我赋值
a[i] = a[j];
*px = *py;
当两个对象来自同一个继承体系时,他们甚至不需要声明为相同类型就可能造成别名。
现在担心的问题是:假如指向同一个对象,当其中一个对象被删,另一个也被删,这会造成不想要的结果。
该怎么办?
比如:
widget& widget:: operator+ (const widget& rhs)
{
delete pd;
pd = new bitmap(*rhs.pb);
return *this; //这里假如*this与rhs是同一个对象。则不好处理。
}
解决方案:
1、证同测试
判断是不是同一个对象,如果是同一个对象,则是自我赋值,不用做任何事。
if(this = &rhs) return *this;
2、记住原先的pb,就是在开辟一个空间存放其原来的地址。我们只需记住在复制pb所指东西前别删除pb;
Bitmap * pOrig = pb; //记住原先的pb
pb = new Bitmap(*rhs.pb); //令pb指向*pb的一个副本
delete pOrig; //删除原先的pb
return *this;
3、直接制作一个副本(引用传递)
widget temp(rhs); //为rhs数据制作一个副本
swap(temp);
4、值传递
swap(rhs);
记住:
1、确保党对象自我赋值时,有良好的行为。其中的技术包括以上四种。
2、确保如果任何函数操作一个以上的对象,而其中多个对象是同一个对象时,其行为一定正确。
还记得条款5中提到编译器在必要时会为我们提供拷贝构造函数和拷贝赋值函数,它们也许工作的不错,但有时候我们需要自己编写自己的拷贝构造函数和拷贝赋值函数。如果这样,我们应确保对“每一个”成员进行拷贝(复制)。
如果你在类中添加一个成员变量,你必须同时修改相应的copying函数(所有的构造函数,拷贝构造函数以及拷贝赋值操作符)。
在派生类的构造函数,拷贝构造函数和拷贝赋值操作符中应当显示调用基类相对应的函数,否则编译器可能又“自作聪明了”。
当你编写一个copying函数,请确保:
(1)复制所有local成员变量;
(2)调用所有基类内的适当copying函数。
但是,我们不该令拷贝赋值操作符调用拷贝构造函数,也不该令拷贝构造函数调用拷贝赋值操作符。想想,一个是拷贝(建立对象),一个是赋值(对象已经存在)。
请记住:
- 1、Copying函数应该确保复制“对象内的所有成员变量”及“所有基类成员”;
- 2、不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放进第三个函数中,并由两个copying函数共同调用。