本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie
经验:确保当对象自我赋值时operator=有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。
示例:没有“证同测试”
#include <iostream> #include <string> using namespace std; class Bitmap{ public: Bitmap(int s):size(s){} Bitmap(const Bitmap &b){ this->size = b.size; } int getSize() const{return size;} private: int size; }; class Widget{ public: Widget(int size){ pb = new Bitmap(size); } Widget &Widget::operator=(const Widget &rhs){ delete pb; //停止使用当前的bitmap pb = new Bitmap(*rhs.pb); //使用rhs's bitmap的副本 return *this; } Bitmap *getBitMap() const{return pb;} private: Bitmap *pb; //指针,指向一个从heap分配而得的对象 }; int main(){ Widget w(1); cout << "before self assignment: " << w.getBitMap()->getSize() << endl; w = w; cout << " after self assignment: " << w.getBitMap()->getSize() << endl; system("pause"); }
输出:
before self assignment: 1
after self assignment: -842150451
解析:
operator=函数内的*this和rhs是同一个对象,delete销毁当前对象的bitmap,也销毁了rhs的bitmap,在函数末尾,Widget用自己持有一个指向已被删除的对象指针创建新的bitmap。所以当自我赋值后,w对象里的值变成了乱码。
纠正1:通过“证同测试”来避免自我赋值
示例:加了“证同测试”
#include <iostream> #include <string> using namespace std; class Bitmap{ public: Bitmap(int s):size(s){} Bitmap(const Bitmap &b){ this->size = b.size; } int getSize() const{return size;} private: int size; }; class Widget{ public: Widget(int size){ pb = new Bitmap(size); } Widget &Widget::operator=(const Widget &rhs){ if(this == &rhs) return *this; //这里加了“证同测试” delete pb;//停止使用当前的bitmap pb = new Bitmap(*rhs.pb); //使用rhs's bitmap的副本 return *this; } Bitmap *getBitMap() const{return pb;} private: Bitmap *pb; //指针,指向一个从heap分配而得的对象 }; int main(){ Widget w(1); cout << "before self assignment: " << w.getBitMap()->getSize() << endl; w = w; cout << " after self assignment: " << w.getBitMap()->getSize() << endl; system("pause"); }
输出:
before selfassignment: 1
after self assignment: 1
纠正2:通过处理“异常安全性”来自动获得“自我赋值安全”的回报
#include <iostream> #include <string> using namespace std; class Bitmap{ public: Bitmap(int s):size(s){} Bitmap(const Bitmap &b){ this->size = b.size; } int getSize() const{return size;} private: int size; }; class Widget{ public: Widget(int size){ pb = new Bitmap(size); } Widget &Widget::operator=(const Widget &rhs){ Bitmap* pOrig = pb; //记住原先的pb pb = new Bitmap(*rhs.pb); //使用rhs's bitmap的副本 delete pOrig; //删除原先的pb return *this; } Bitmap *getBitMap() const{return pb;} private: Bitmap *pb; //指针,指向一个从heap分配而得的对象 }; int main(){ Widget w(1); cout << "before self assignment: " << w.getBitMap()->getSize() << endl; w = w; cout << " after self assignment: " << w.getBitMap()->getSize() << endl; system("pause"); }
输出:
before selfassignment: 1
after self assignment: 1
解析:如果“newBitmap”抛出异常,pb保持原状;这段代码也能处理自我赋值。还可以把“证同测试”再次放回函数起始处,双重保险,不过有其他执行速度等的代价
纠正3:copy and swap技术
示例:
<pre name="code" class="cpp"> Widget &Widget::operator=(const Widget &rhs){ Widget temp(rhs); swap(temp); return *this; } 或 Widget &Widget::operator=( Widget rhs){ //将”copying动作”从函数本体移到“函数参数构造阶段” swap(rhs); return *this; }