Effective c++ 條款11:在operator=中處理“自我賦值”
阿新 • • 發佈:2019-02-17
自我賦值發生在物件被賦值給自己時,且有些時候自我賦值不是這麼容易能被看出來,比如
a[i] = a[j]; //存在自我賦值的可能性(i==j時 )
*px = *py; //存在自我賦值的可能性(px和py指向同一物件)
這些自我賦值是別名帶來的結果,所謂別名就是有一個以上的方法指稱某物件。如果某段程式碼用來操作指向多個相同型別物件的pointers或references,就要考慮自我賦值的可能性。
實際上兩個物件如果來自同一個繼承體系,它們甚至不需宣告為相同型別就可能造成別名。
證同測試(identity test)
Widget& Widget::opearator=(const Widget& rhs) {
if (&rhs == this) return *this;
delete pb;
pb = new Bitmap(rhs.pb);
return *this;
}
然而這一版本並不具備異常安全性,當因分配時記憶體不足等問題導致異常時,pb將指向一塊被刪除的Bitmap。
注意在複製所指內容之前別刪除
Widget& Widget::opearator=(const Widget& rhs) {
Bitmap* pOrig = pb;
pb = new Bitmap(rhs.pb);
delete pOrig;
return *this;
}
現在,如果new操作丟擲異常,pb將保持現狀,且即使沒有證同測試,這段程式碼也能處理自我賦值。
如果想要在這段程式碼前加入證同測試,需要考慮自我賦值發生的概率,畢竟比較也是需要時間的。
copy and swap
Widget& Widget::opearator=(const Widget& rhs) {
Widget temp(rhs);
swap(temp);
return *this;
}
另一種類似的方法是:
Widget& Widget::opearator=(Widget rhs) {//注意是值傳參
swap(rhs);
return *this;
}
這種方法犧牲了清晰性,然而將copying動作從函式本體內移至函式引數構造階段,令編譯器有時生成更高效的程式碼。