条款11:在 operator= 中处理自我赋值
Handle assignment to self in operator=.
潜在的自我赋值以及危害
自我赋值并不容易被肉眼辨别:
a[i] = a[j];
*px = *py;
一份不安全的复制函数实现:
Widget& Widget::operator=(const Widget& rhs) {
delete pb;
pb = new Bitmap(*rhs.pb); // 如果是自我赋值,此时 *rhs.pb 指向的空间已经被释放;
return *this;
}
解决办法
传统做法是证同测试(identity test):
Widget& Widget::operator=(const Widget& rhs) {
if (this == &rhs) return *this; // 证同测试;
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
但是这个版本不具备异常安全性(exception safety),即当 new Bitmap
出现异常时,pb
会指向一个被删除的空间,为此可以将重点放到实现异常安全性上:
Widget& Widget::operator=(const Widget& rhs) {
Bitmap* pOrig = pb; // 记住原先的 pb;
pb = new Bitmap(*rhs.pb); // 令 pb 指向一个副本;
delete pOrig; // 删除原先的 pb;
return *this;
}
这种做法虽然会造成额外的性能开销,但是却解决了自我赋值和异常安全的问题。如果程序很关心性能,可以加上证同测试,但这将引入一个新的控制流分支(control flow),它同样会降低执行速度。
Last updated
Was this helpful?