第九章:過載賦值運算子中需要注意的兩個問題

穆晨發表於2017-01-27

前言

       如果系統自動生成的賦值運算子過載函式不合乎你的要求,那麼就應當定製自己的賦值運算子。

       然而,定製賦值運算子有兩點是非常值得注意的,本文將講解這兩點,讓你寫出更優質的 =運算子。

第一點:請返回 reference to *this

       我們經常使用如 "a=b=c=1" 這種形式的連鎖賦值語句,而過載的賦值運算子自然也應當能夠這樣使用。

       因此,在過載運算子函式末尾請寫上如這樣的語句 return *this;

       除了賦值運算子,+=,-=這樣的賦值運算子同樣需要這樣做。

第二點:處理好自我賦值

       首先,我們看一段問題程式碼:

 1 // 點陣圖資源類
 2 class Bitmap { /*......*/ };
 3 
 4 // 點陣圖資源管理類
 5 class Widget {
 6 public:
 7     //......
 8     Widget & operator=(const Widget & rhs);
 9     //......
10 private:
11     //......
12     Bitmap *pb;    // 點陣圖資源。指標型別,指向 heap 分配而得的空間
13     //......
14 };
15 
16 Widget & Widget::operator=(const Widget & rhs)
17 {
18     delete pb;    // 刪除原有資源
19     pb = new Bitmap(*rhs.pb);    // 申請新的資源並存放右運算元的資料
20     return *this;
21 }

       問題出在過載函式中,如果左右運算元是相同的物件,delete 掉原有資源之後,所有資料資訊就全丟了。

       因此,運算子過載函式需要加上一個證同測試:

 1 Widget & Widget::operator=(const Widget & rhs)
 2 {
 3     // 加入證同測試
 4     if (this == &rhs)
 5         return *this;
 6 
 7     delete pb;    // 刪除原有資源
 8     pb = new Bitmap(*rhs.pb);    // 申請新的資源
 9 
10     return *this;
11 }

       但這依然不是最好的做法:因為 new 有可能失敗,導致資源丟失。

       下面這個精心設計的過載函式才是我們需要的:

1 Widget & Widget::operator=(const Widget & rhs)
2 {
3     Bitmap * pOrig = pb;
4     pb = new Bitmap(*rhs.pb);
5     delete pOrig;
6 
7     return *this;
8 }

       這個實現就保證了賦值的安全,健壯,是個非常可取的方案。

小結

       賦值運算子還有一些其他的非常可取的實現,這裡就不一一講解了。

相關文章