好久沒寫東東;今天寫點。
很多人喜歡使用C++中的引用,盡力用它來替代指針的使用,來防止指針固有的爲人詬病的缺陷;幾年前,我所在的一個大型C++項目就是這樣的,一些天才的技術狂人非常偏好使用引用,導致引用充滿角落中。最開始,我還覺得用的不錯,效率高還不失簡潔性,相信很多人都有此看法。不過,一次痛苦的調試經歷讓我開始重新審視C++中的引用。
大概的程序是這樣的(實際程序比它要複雜很多,這裏爲了敘述問題進行簡化):
1: class CB2: {
3: };
4: class CA5: {
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 CB2: {
3: };
4: class CA5: {
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 line14: 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的用法纔是比較能接受的!