C/C++中的指針讓程序員有了更多的靈活性,但它同時(shí)也是一把雙刃劍,如果用的不好,則會(huì)讓你的程序出現(xiàn)各種各樣的問題,有人說,C/C++程序員有一半的工作量是花在處理由指針引起的bug上,可想而知,指針中包含的陷阱是多么可怕。既然如此,我們?cè)诰帉懘a的時(shí)候就應(yīng)該把好關(guān)。 要想在編寫代碼的時(shí)候盡可能避免指針帶來的問題,就需要知道不恰當(dāng)?shù)氖褂弥羔樀降讜?huì)引發(fā)哪些問題, 又該如何去避免它?下面一起來總結(jié)在使用指針時(shí)容易遇到的問題。 程序在運(yùn)行的時(shí)候需要內(nèi)存,同時(shí)我們也知道內(nèi)存是有限的,是計(jì)算機(jī)特別寶貴的資源,對(duì)于使用完的內(nèi)存,應(yīng)當(dāng)及時(shí)的歸還給操作系統(tǒng)。 在c/c++中,如果是棧上的內(nèi)存(比如說函數(shù)中的局部非靜態(tài)變量),在使用完之后,操作系統(tǒng)會(huì)幫我們自動(dòng)回收;但是如果是通過動(dòng)態(tài)分配得到的堆上的內(nèi)存,需要我們手動(dòng)釋放。 如果我們?cè)诔绦蛑型酸尫胚@些動(dòng)態(tài)內(nèi)存,而程序又是會(huì)持續(xù)運(yùn)行的服務(wù)進(jìn)程,會(huì)導(dǎo)致內(nèi)存占用越來越高,輕者致殘影響系統(tǒng)性能,重者致命導(dǎo)致進(jìn)程崩潰。 總之一句話,不再用到的內(nèi)存沒有釋放,就叫做內(nèi)存泄露,內(nèi)存泄露的問題很嚴(yán)重。好了,讓我們看幾個(gè)內(nèi)存泄露的案例。 在C/C++中,通過動(dòng)態(tài)內(nèi)存分配函數(shù)(如malloc系統(tǒng)函數(shù))或者new運(yùn)算符分配的動(dòng)態(tài)內(nèi)存在使用完之后需要手動(dòng)釋放。否則會(huì)造成內(nèi)存泄露。 建議:代碼編寫時(shí)注意malloc/free, new/delete成對(duì)使用 即使在malloc/new后顯示調(diào)用了free/delete釋放內(nèi)存,但是由于異常可能會(huì)導(dǎo)致釋放內(nèi)存的free/delete語(yǔ)句得不到執(zhí)行,也會(huì)發(fā)生內(nèi)存泄露,下面的例子就是這種情況。 從運(yùn)行結(jié)果來看,類的析構(gòu)函數(shù)沒有被執(zhí)行,可推知delete語(yǔ)句并沒有得到執(zhí)行。 有人會(huì)說,這還不簡(jiǎn)單,直接在catch語(yǔ)句的cout < 'something="" has="" gone="" wrong'="">< endl;下面之后加個(gè)delete=""> 沒錯(cuò),這只是個(gè)幾十行代碼的測(cè)試程序,你可能一下就看出問題了,但是如果你面對(duì)的是一個(gè)龐大的工程時(shí)候,我想你內(nèi)心一定是好崩潰的。還有更好的辦法來解決這種問題,就是智能指針,后面會(huì)有專門的文章介紹。 建議:C++代碼代碼中多注意使用智能指針 野指針也叫懸掛指針,是指向“垃圾”內(nèi)存的指針,使用“野指針”會(huì)讓程序出現(xiàn)不確定的行為。 注意,野指針不是NULL指針, 它比NULL指針更容易犯錯(cuò),因?yàn)樗荒芡ㄟ^形如 if (NULL == p)的判斷語(yǔ)句來預(yù)防,只能我們自己在寫代碼時(shí)多注意。 指針p被free或者delete之后,沒有置為NULL,讓人誤以為p是個(gè)合法的指針,事實(shí)上free或delete只是把指針?biāo)傅膬?nèi)存給釋放掉,但是指針的值還是這塊內(nèi)存的地址,只不過這塊內(nèi)存已經(jīng)被回收了不能被該進(jìn)程再使用,下面的例子就是一個(gè)典型的使用野指針的案例。 建議:free或delete之后將相應(yīng)的指針設(shè)置為NULL 在創(chuàng)建指針變量p時(shí)忘了初始化,p的值是個(gè)隨機(jī)的垃圾值,此時(shí)讀寫該指針都是危險(xiǎn)的,程序會(huì)產(chǎn)生不確定的行為 建議:定義指針變量的時(shí)候盡量初始化,哪怕初始化為NULL也好 c/c++中,局部變量是存放在棧中的,它的特點(diǎn)是隨函數(shù)調(diào)用時(shí)創(chuàng)建隨函數(shù)結(jié)束時(shí)銷毀,因此在程序中將局部變量的地址返回后賦值給一個(gè)指針,這個(gè)指針指向的是一個(gè)已經(jīng)被回收的內(nèi)存,這也是一種野指針。 看看下面的例子,原本是想將fun函數(shù)中的變量i的地址返回給p,用p訪問這個(gè)變量,這個(gè)打印出*p是32767,并不是變量i的值8。像這種bug,一旦在大的項(xiàng)目中出現(xiàn)是很難定位的。 建議:不要在函數(shù)中返回局部變量的地址,如果代碼的邏輯非要是一個(gè)局部變量的地址,那么該局部變量一定要申明為static類型,因?yàn)閟tatic變量的生存期是整個(gè)程序運(yùn)行期間 大家都知道,在程序中不能使用NULL指針,但是如果不注意,程序中還是有可能在你的意料之外就使用到NULL指針,下面看兩個(gè)比較容易出問題的例子。 動(dòng)態(tài)內(nèi)存分配函數(shù)分配內(nèi)存的時(shí),有可能會(huì)分配失敗,此時(shí)返回NULL
從程序運(yùn)行結(jié)果來看,malloc分配失敗返回NULL賦給p,再通過p訪問其所指向的0地址內(nèi)存內(nèi)容時(shí),出現(xiàn)'Segmentation fault'錯(cuò)誤。 建議:在使用內(nèi)存分配函數(shù)分配內(nèi)存的時(shí)候,應(yīng)該用i f(p==NULL) 或if(p!=NULL)進(jìn)行防錯(cuò)處理。 此外,在含有指針參數(shù)的函數(shù),也是有可能會(huì)誤用到NULL指針,當(dāng)調(diào)用該函數(shù)時(shí)傳遞的指針是個(gè)空指針,如果沒有if(p!=NULL) 的判斷條件,那么在后面使用指針的時(shí)候麻煩就大了,下面的例子就是這種情況。
建議:對(duì)于含有指針參數(shù)的函數(shù),也應(yīng)當(dāng)在函數(shù)入口處用if(p==NULL) 或if(p!=NULL)進(jìn)行防錯(cuò)處理。 ●本文編號(hào)287,以后想閱讀這篇文章直接輸入287即可 ●輸入m獲取文章目錄 |
|
|