class Widget
{
Widget w;
...
}
w=w;//自我赋值
有时候自我赋值也不是这么容易能看出来的
a[i]=a[j]; //i和j有相同的值,潜在的自我赋值
*px=*py;//指向同一个东西,也是潜在的自我赋值
有时自我赋值并不安全
class BItmap{.....};
class Widget
{
...
private:
Bitmap *pb;
};
Widget & Widget::operator=(const Widget &rhs) //一份不安全的operator=实现版本
{
delete pd; //删除了pd;
pd= new Bitmap(*rhs.pb); //使用rhs.pd版本(复件)
return *this ;
}
问题来了,如果rhs.pb和pd有可能是同一个对象,那么当删除了pd,然后pd指向了一个已被删除的对象!
解决:
欲阻止这种错误,传统做法是在最前面加一个“证同测试”
Widget & Widget::operator=(const Widget & rhs)
{
if(this == rhs) ruturn *this ;//证同测试,若是自我赋值就不做任何事。
delete pd;
pd=new Bitmap(* rhs .pd);
return *this;
}
但是这种版本还是存在异常方面的麻烦。如果“new Bitmap”导致异常(不论是因为分配时内存不足或因为Bitmap的copy构造函数抛出异常),pd指针被清空后,指向一块被删除的Bitmap;这样的指针有害,你无法安全地删除它们,甚至无法安全地读取它们。
除了用“证同测试”,也可以用以下方法,即没有在复制pb所指东西之前别删除pd;
Widget& Wiget::operator=(const Widget & rhs)
{
Bitmanp * pOrig =pd;
pd= new Bitmap( *rhs.pb);
delete pOrig;
return *this;
}