先举几个自我赋值的例子:
例:Widgetw;
w = w;
a[i] = a[j]; //i == j or i!= j
*px = *py;// px,py指向同个地址;
以上情况都是对“值”的赋值,但我们涉及对“指针”和“引用”进行赋值操作的时候,才是我们真正要考虑的问题了。
看下面的例子:
Widget& Widget::operator=(constWidget& rhs)
{
delete pb; //这里对pb指向内存对象进行delete,试想 *this == rhs?情况会如何
pb = new Bitmap(*rhs.pb); //如果*this == rhs,那么这里还能new吗?“大事不妙”。
return *this;
}
也许以下代码能解决以上问题:
Widget& Widget::operator=(const Widget& rhs)
{
if (this == &rhs)
return *this; //解决了自我赋值的问题。
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
“许多时候一群精心安排的语句就可以导出异常安全(以及自我赋值安全)的代码。”,以上代码同样存在异常安全
问题。
Widget& Widget::operator=(const Widget& rhs)
{
Bitmap *pOrig = pb; //记住原先的pb
pb = newBitmap(*rhs.pb); //令pb指向*pb的一个复本
delete pOrig; //删除原先的pb
return *this; //这样既解决了自我赋值,又解决了异常安全问题。自我赋值,将pb所指对象换了个存储地址。
}
请记住:
- 确保当对象自我赋值时operator =有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。
- 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。