今天看了一段C++Primer的代码:p506
//use-counted assignment operator;use is a pointer to a shared use count Sales_item& Saler_item::operator=(const Sales_item &rhs) { ++*rhs.use; decr_use(); p = rhs.p; use = rhs.use; return *this; }
其中 void decr_use() { if(--*use==0) { delete p; delete use; } }问题是:上面是如何处理自我赋值问题的。我看了半天,不太理解。
后来才发现:它所谓的防止自我赋值的核心问题就是要防止自我赋值过程中,被赋值对象被提前删除,而造成程序出错。注释后结果:
//use-counted assignment operator;use is a pointer to a shared use count Sales_item& Saler_item::operator=(const Sales_item &rhs) { ++*rhs.use; //右操作数的使用计数加1,这样就可以避免左右操作数相同,造成左操作数提前析构 //因为调用decr_use后,左操作数就至少是2了,减1后不为零,就不会出现delete操作 decr_use(); //这个decr_use是左操作数调用的,左操作数的使用计数减1 p = rhs.p; //将右操作数的指针赋给左操作数 use = rhs.use; return *this;//返回左操作数的引用 } 其中 void decr_use() { if(--*use==0) { delete p; delete use; } }
现在来看Meyers的Effective C++中的“自我赋值”处理 p54
看如下代码:
Widget& Widget::operator=(const Widget&rhs) { delete pb; //停止使用当前的bitmap pb = new Bitmap(*rhs.pb);//使用rhs的bitmap副本 return *this; }
欲阻止这种错误,传统做法是借有operator=最前面的一个证同测试达到自我赋值的检验目的:
Widget&
Widget::operator=(const Widget&rhs)
{
if (this==&rhs) return *this;//证同测试
delete pb; //停止使用当前的bitmap
pb = new Bitmap(*rhs.pb);//使用rhs的bitmap副本
return *this;
}
不过这一改进仍有一个麻烦,那就是当new Bitmap出现异常(不论是因为分配时内存不足或因为Bitmap的copy构造函数抛出异常),Widget最终会持有一个指针指向一块被删除的Bitmap。这样的指针是有害的。你无法安全删除它们,甚至无法安全读取它们。那么,我们要做的就是让operator=具有异常安全性,而且在operator=具有异常安全性后往往能够自动获得“自我赋值安全”的回报。修改如下:
Widget& Widget::operator=(const Widget&rhs) { Bitmap* pOrig = pb; pb = new Bitmap(*rhs.pb);//使用rhs的bitmap副本 delete pOring; return *this; }