”自我赋值”发生在对象被赋值给自己时:
class Widget { ... };
Widget w;
...
w = w;                  // 赋值给自己
a[i] = a[j];            // 潜在的自我赋值
*px = *py;              // 潜在的自我赋值class Base { ... };
class Derived: public Base { ... };
void doSomething(const Base& rb, Derived* pd);  // rb和*pd有可能其实是同一对象尝试自我管理资源
class Bitmap { ... };
class Widget {...
private:Bitmap* pb;         // 指针,指向一个从heap分配而得的对象
};
// 一个不安全的operator=实现版本
Widget& Widget::operator=(const Widget& rhs) {delete pb;                      // 停止使用当前的bitmappb = new Bitmap(*rhs.pb);       // 使用rhs's bitmap的副本return *this;                   // 见条款10
}可能出现的问题就是,*this和rhs可能是同一个对象,最后会导致自己持有一个指针指向一个已被删除的对象!
自我安全性
Widget& Widget::operator=(const Widget& rhs) {if (this == rhs) return *this;          // 证同测试// 如果是自我赋值,就不做任何事情delete pb;pb = new Bitmap(*rhs.pb);return *this;
}以上代码确实解决了自我赋值的问题,但是会引发异常的问题,如果new Bitmap导致异常了,那么Widget最终会持有一个指针指向一块被删除的Bitmap。
异常安全性
Widget& Widget::operator=(const Widget& rhs) {Bitmap* pOrig = pb;                     // 记住原先的pbpb = new Bitmap(*rhs.pb);delete pOrig;                           // 删除原先的pbreturn *this;
}copy and swap
class Widget {
...
void swap(Widget& rhs);
...
};
Widget& Widget::operator=(const Widget& rhs) {Widget temp(rhs);swap(temp);return *this;
}
Widget& Widget::operator=(Widget rhs) { // 注意这里是传值swap(rhs);                  return *this;
}总结
- 确保当对象自我赋值时operator=有良好行为。其中技术包括比较”来源对象”和”目标对象”的地址、精心周到的语句顺序、以及copy-and-swap.
- 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。