轉載位址: https://mp.weixin.qq.com/s/8CMN1z4kSJ8deKalgIlN-w
C/C++中的指針讓程式員有了更多的靈活性,但它同時也是一把雙刃劍,如果用的不好,則會讓你的程式出現各種各樣的問題,有人說,C/C++程式員有一半的工作量是花在處理由指針引起的bug上,可想而知,指針中包含的陷阱是多麼可怕。既然如此,我們在編寫代碼的時候就應該把好關。
要想在編寫代碼的時候盡可能避免指針帶來的問題,就需要知道不恰當的使用指針到底會引發哪些問題, 又該如何去避免它?下面一起來總結在使用指針時容易遇到的問題。
1
避免記憶體洩露
程式在運作的時候需要記憶體,同時我們也知道記憶體是有限的,是計算機特别寶貴的資源,對于使用完的記憶體,應當及時的歸還給作業系統。
在c/c++中,如果是棧上的記憶體(比如說函數中的局部非靜态變量),在使用完之後,作業系統會幫我們自動回收;但是如果是通過動态配置設定得到的堆上的記憶體,需要我們手動釋放。
如果我們在程式中忘了釋放這些動态記憶體,而程式又是會持續運作的服務程序,會導緻記憶體占用越來越高,輕者緻殘影響系統性能,重者緻命導緻程序崩潰。
總之一句話,不再用到的記憶體沒有釋放,就叫做記憶體洩露,記憶體洩露的問題很嚴重。好了,讓我們看幾個記憶體洩露的案例。
在C/C++中,通過動态記憶體配置設定函數或者new運算符配置設定的動态記憶體在使用完之後需要手動釋放。否則會造成記憶體洩露。
建議:代碼編寫時注意malloc/free, new/delete成對使用
即使在malloc/new後顯示調用了free/delete釋放記憶體,但是由于異常可能會導緻釋放記憶體的free/delete語句得不到執行,也會發生記憶體洩露,下面的例子就是這種情況。
從運作結果來看,類的析構函數沒有被執行,可推知delete語句并沒有得到執行。
有人會說,這還不簡單,直接在catch語句的cout << "Something has gone wrong" << endl;下面之後加個delete t不就行了?
沒錯,這隻是個幾十行代碼的測試程式,你可能一下就看出問題了,但是如果你面對的是一個龐大的工程時候,我想你内心一定是好崩潰的。還有更好的辦法來解決這種問題,就是智能指針,後面會有專門的文章介紹。
建議:C++代碼代碼中多注意使用智能指針
2
不要使用野指針
野指針也叫懸挂指針,是指向“垃圾”記憶體的指針,使用“野指針”會讓程式出現不确定的行為。
注意,野指針不是NULL指針, 它比NULL指針更容易犯錯,因為它不能通過形如 if (NULL == p)的判斷語句來預防,隻能我們自己在寫代碼時多注意。
指針p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指針,事實上free或delete隻是把指針所指的記憶體給釋放掉,但是指針的值還是這塊記憶體的位址,隻不過這塊記憶體已經被回收了不能被該程序再使用,下面的例子就是一個典型的使用野指針的案例。
建議:free或delete之後将相應的指針設定為NULL
在建立指針變量p時忘了初始化,p的值是個随機的垃圾值,此時讀寫該指針都是危險的,程式會産生不确定的行為
建議:定義指針變量的時候盡量初始化,哪怕初始化為NULL也好
c/c++中,局部變量是存放在棧中的,它的特點是随函數調用時建立随函數結束時銷毀,是以在程式中将局部變量的位址傳回後指派給一個指針,這個指針指向的是一個已經被回收的記憶體,這也是一種野指針。
看看下面的例子,原本是想将fun函數中的變量i的位址傳回給p,用p通路這個變量,這個列印出*p是32767,并不是變量i的值8。像這種bug,一旦在大的項目中出現是很難定位的。
建議:不要在函數中傳回局部變量的位址,如果代碼的邏輯非要是一個局部變量的位址,那麼該局部變量一定要申明為static類型,因為static變量的生存期是整個程式運作期間
3
不要使用NULL指針
大家都知道,在程式中不能使用NULL指針,但是如果不注意,程式中還是有可能在你的意料之外就使用到NULL指針,下面看兩個比較容易出問題的例子。
動态記憶體配置設定函數配置設定記憶體的時,有可能會配置設定失敗,此時傳回NULL
從程式運作結果來看,malloc配置設定失敗傳回NULL賦給p,再通過p通路其所指向的0位址記憶體内容時,出現"Segmentation fault"錯誤。
建議:在使用記憶體配置設定函數配置設定記憶體的時候,應該用i f(p==NULL) 或if(p!=NULL)進行防錯處理。
此外,在含有指針參數的函數,也是有可能會誤用到NULL指針,當調用該函數時傳遞的指針是個空指針,如果沒有if(p!=NULL) 的判斷條件,那麼在後面使用指針的時候麻煩就大了,下面的例子就是這種情況。
建議:對于含有指針參數的函數,也應當在函數入口處用if(p==NULL) 或if(p!=NULL)進行防錯處理。