effective C++ 讀書筆記 條款11
阿新 • • 發佈:2017-07-01
col tor 變量 pre amp 副本 swap 基本 目標
條款11: 在operator= 中處理“自我賦值”
在實現operator=時考慮自我賦值是必要的就像 x=y 。我們不知道變量x與y代表的值是否為同一個值(把x和y說成是一個指針更恰當一點)。
例如以下
第一版:
#include <iostream> using namespace std; class bitmap { public: bitmap() { cout<<"調用bitmap()無參構造函數"<<endl; } bitmap(const bitmap& bt) { this->i = bt.i; cout<<"調用bitmap()拷貝構造函數"<<endl; } ~bitmap() { } private: int i; }; class Widget { public: Widget() { pb = new bitmap(); } Widget(const Widget& wd) { this->pb = wd.pb; } public: Widget& operator=(const Widget& rhs); private: bitmap* pb; //定義一個從heap分配而得的對象 }; //第一版賦值函數: Widget& Widget::operator=(const Widget& rhs) { delete pb; pb = new bitmap(*rhs.pb); return *this; } //這一版函數的pb在使用前清理掉之前的pb指向。再接受一個new出來的新對象,看著非常順理成章,可是 //當this與函數參數rhs相等的時候,pb = new bitmap(*rhs.pb);由於我們已經把*rhs.pb delete掉了。int main() { Widget w1; Widget w2; w1 = w2; return 0; } /* 調用bitmap()無參構造函數 調用bitmap()無參構造函數 調用bitmap()拷貝構造函數 Press any key to continue */
第二版:
//第二版賦值函數: Widget& Widget::operator=(const Widget& rhs) { if (this == &rhs) { return *this; } delete pb; pb = new bitmap(*rhs.pb); return *this; } //這個版本號行的通,賦值函數基本上是能夠接受的,可是不見得是安全的,由於當new產生異常時pb依舊是一個 //不確定的指針。
第三版:
//第三版賦值函數: Widget& Widget::operator=(const Widget& rhs) { bitmap *pOrig = pb; pb = new bitmap(*rhs.pb); delete pOrig; return *this; } //第三版函數在開始的時候用pOrig記錄了pb。當new沒有異常時我們再把pb原來的指向空間釋放掉 //從而提高了安全性。這樣的方法也相同可以處理自我賦值。假如這裏rhs=*this。我們先對原來的 //bitmap做了一份備份,刪除原bitmap後,指向了我們的那一份備份,也許這樣的處理自我賦值的方法 //不是非常好。可是行的通,在保證安全性的情況下採用這樣的辦法非常不錯。
第四版:
#include <iostream> using namespace std; class bitmap { public: bitmap() { cout<<"調用bitmap()無參構造函數"<<endl; } bitmap(const bitmap& bt) { this->i = bt.i; cout<<"調用bitmap()拷貝構造函數"<<endl; } ~bitmap() { } private: int i; }; class Widget { public: Widget() { cout<<"調用Widget()無參構造函數"<<endl; pb = new bitmap(); } Widget(const Widget& wd) { cout<<"調用Widget()拷貝參構造函數"<<endl; this->pb = wd.pb; } void my_swap(Widget& rhs); public: Widget& operator=(const Widget& rhs); private: bitmap* pb; //定義一個從heap分配而得的對象 }; //第四版賦值函數: void Widget::my_swap( Widget& rhs) { pb = rhs.pb; } Widget& Widget::operator=(const Widget& rhs) { Widget temp(rhs);//防止改變rhs my_swap(temp); return*this; } //第四版賦值函數利用的是copy and swap技術,這個技術在條款29其中 //有具體說明。還沒認真看,這裏就不解釋了。 //第四版也能夠這樣用: Widget& Widget::operator=(Widget rhs) { my_swap(rhs); //事實上本質上是一樣的,由於傳遞的參數是值傳遞,所以這裏傳遞的是rhs的一個副本。相當於Widget temp(rhs);主要就是防止rhs被改變。 return*this; } int main() { Widget w1; Widget w2; w1 = w2; return 0; } /* 調用Widget()無參構造函數 調用bitmap()無參構造函數 調用Widget()無參構造函數 調用bitmap()無參構造函數 調用Widget()拷貝參構造函數 Press any key to continue */
總結:
1:確保當對象自我賦值時 operator= 有良好行為,當中技術包含比較“原來對象”和“目標對象”的地址。、精心周到的語句順序,以及copy and swap
2:確定不論什麽函數假設操作一個以上的對象,而當中多個對象是同一個對象時,其行為仍然正確。
effective C++ 讀書筆記 條款11