自我賦值發生在對象被賦值給自己:
class Widget {
...
}
Widget w ;
…
w = w // 賦值給自己
還有一個隱含的會發生自我賦值的例子:
a[i] = a[j];//當i = j時
下面有這樣一個類:
class Bitmap{};
class Widget {
...
private :
Bitmap *pb;
};
l 版本一
Widget& Widget::operator= (const Widget& rhs){
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
注意:這裡存在一個問題,那就是如果rhs所指的對象就是this。Delete pb後,就把this的pb刪除了,所以不行。
欲阻止這樣的錯誤,可以加上一個證同測試:
l 版本二
Widget& Widget::operator= (const Widget& rhs){
if(this == rhs) return *this; // 證同測試
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
這樣做法是可以的,但是還有一個問題是如果在new Bitmap時,出現的異常,則會使widget對象最終會持有一個指標指向一塊被刪除的bitmap。這樣的指標是有害的,你無法安全的刪除它們,也無法安全的讀取它們。
但是精心安排一下,是可以避免這個錯誤的:
l 版本三:
Widget& Widget::operator= (const Widget& rhs){
Bitmap *obj = rhs.pb;
pb = new Bitmap(*rhs.pb);
delete obj;
return *this;
}
現在如果new Bitmap出現的異常,pb也會保持原狀。注意,雖然我們沒有加入證同測試,但是上面的代碼也可以處理自我賦值現象。
版本四:
針對版本三還有一個替換版本:
class Widget {
public:
...
swap(Widget& rhs);
private :
Bitmap *pb;
};
Widget& Widget::operator= (const Widget& rhs){
Widget temp(rhs);
swap(temp);
return *this;
}
這項技術被稱為copy and swap技術。
- 請記住:
- 確保當對象自我賦值時operator=有良好的行為。其中的技術包括
- 比較“來來源物件”與“目標對象”的地址
- 精心周到的語句順序
- Copy and swap技術
- 確定任何函數如果操作一個以上的對象,而其中多個對象是同一個對象時,其行為也是正確的