都是“引用”惹得禍!

好久沒寫東東;今天寫點。

很多人喜歡使用C++中的引用,盡力用它來替代指針的使用,來防止指針固有的爲人詬病的缺陷;幾年前,我所在的一個大型C++項目就是這樣的,一些天才的技術狂人非常偏好使用引用,導致引用充滿角落中。最開始,我還覺得用的不錯,效率高還不失簡潔性,相信很多人都有此看法。不過,一次痛苦的調試經歷讓我開始重新審視C++中的引用。

大概的程序是這樣的(實際程序比它要複雜很多,這裏爲了敘述問題進行簡化):

   1: class CB
   2: {
   3: };
   4: class CA
   5: {
   6: public:
   7:     CA(const CB& cb): m_cb(cb) {}
   8: private:
   9:     const CB& m_cb;
  10: };
  11:  
  12: void func_special(CB * pCB)
  13: {
  14:     ……;
  15:     delete pCB;
  16: }
  17:  
  18: int main()
  19: {
  20:     CB * pobj1 = new CB;
  21:     CA * pObj2 = new CA(*pobj1); 
  22:     func_special(pobj1);
  23:
  24:     pObj2->func();
  25: }

當時,程序總是在執行CA中函數時報告“Segment Fault”; 後來經過查找發現,pObj2中引用的m_cb已經被其它函數銷燬了,這導致訪問非法內存的問題。

另外一種錯誤的寫法:

   1: CA* func_special()
   2: {
   3:     CB Obj;
   4:     return new CB(Obj); //ERROR, CA是使用了Obj的引用,這個對象將會在函數退出後銷燬。
   5: }

再看另外一種寫法:

   1: class CB
   2: {
   3: };
   4: class CA
   5: {
   6: public:
   7:     typedef CB * ref_ptr;
   8:     void func_special()
   9:     {
  10:          ref_ptr& cb = m_pCB;
  11:
  12:          auto_destroy AutoDel(cb);
  13:          //MUST add following line
  14:          cb = NULL;
  15:     }
  16: private:
  17:     CB * m_pCB;
  18: }

另外一個缺陷是傳遞參數的時候使用非const類型的對象引用,譬如下面的code:

   1: void func( CB& cb)
   2: {
   3:     cb.name = "yanshuo";
   4: }
   5:  
   6: void funcA(const CB& cb)
   7: {
   8: }
   9:  
  10: void funcC(CB * pcb)
  11: {
  12:     if (NULL == pcb)
  13:     {//Handle error
  14:         //print error message.
  15:         return;
  16:     }
  17:     pcb->name = "yanshuo";
  18: }
  19:  
  20: int main()
  21: {
  22:     CB cb;
  23:     func(cb); //func會通過引用的方式改變傳入對象。
  24:     funcA(cb); //Good code.const類型的應用
  25:     funcC(&cb); //提醒程序員:這裏要傳入指針,該函數有可能改變它的內容。
  26:     return 0;
  27: }

你會發現,func悄悄地把傳入參數的值改變了,其他程序員當使用該函數時,有可能沒太注意到這個函數會改變傳入變量的值,在大型的項目中非常忌諱該用法;funcA函數是推薦用法,但是要注意該對象是一定沒有被銷燬的,謹慎;funcC通過設置傳入參數爲指針類型,意在提醒其他人,小心,傳入的是指針,你的傳入參數有可能被修改。

綜上所述,儘量在大型項目中使用C++的引用,只有FuncA的用法纔是比較能接受的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章