都是“引用”惹得祸!

好久没写东东;今天写点。

很多人喜欢使用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的用法才是比较能接受的!

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