好久没写东东;今天写点。
很多人喜欢使用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的用法才是比较能接受的!