很多程式初學者比較沒有在注意一些Memory處理上的問題。其實只要平時稍微注意一下,就可以避免掉很多問題,而且也可以讓你的程式更好以及更穩定。
[編輯] Text
首先,是指標變數內容的問題。通常各位在使用指標時,可能習慣不給予初始值。其實這會造成一些問題。所以建議大家宣告指標變數時一律給予初值。若無法在宣告的同時一併配置記憶體,那麼請給予NULL作為初值。例如
TList *myList = NULL;另外,許多在delete後,大家可能也就不再理會該指標的內容了。其實,這也是會造成一些麻煩。因為記憶體被delete可能只是系統作一個記號在記憶配置表中,表示該記憶體是free的。原來的記憶體內還是有原先的內容。但是你的程式一個不注意,又去把原來的指標拿起來用。如果馬上就出錯的話,這樣還好。偏偏因為原來的內容都還在,所以這個錯誤會延遲產生影響。這種類型的Bug特別難抓!因為,你根本找不到引發問題的所在,如果你有個地方一直發生 Access Violation,可是該地方的程式碼你已經check過十幾次了,還是找不問題,那很可能你就是遇到這樣的問題。以前在寫一些程式時,我就曾經為了這樣的Bug,弄了三天。可見其傷害有多大。
所以,當delete某指標後,其務必將其內容設為NULL。一方面是使用NULL指標,一定是馬上出錯。所以你的Bug一下就會抓到。另外一個理由是如果你不小心重複delete同一個物件時,一樣會發生延遲影響的錯誤。但是delete一個NULL指標,在BCB內是什麼也不做。所以不用擔心會發生問題。
總結以上提供下面幾個比較方便MACRO給大家使用:
SAFENEW SAFEDELETE SAFEDELETE_ARRAY其中,SAFENEW是用來配置記憶體使用。與一般new不同的是,當配置記憶體產生Exception或是配置不出記憶體時,會產生一個訊息視窗警告。並且,將該指標內容設定為 NULL。
而SAFEDELETE再delete前會先檢查該指標是否為NULL。若是就進行delete動作,並且在delete完後將該指標內容設定為NULL。SAFEDELETE_ARRAY也是一樣的作用,只是他是用來刪除陣列指標用的。例如:
TList *myList = NULL; char *string = NULL ; SAFENEW(myList, TList()); SAFENEW(string, char[10]); ... SAFEDELETE(myList); SAFEDELETE(string);上面這三個Macro你可在本文最後的程式列表找到。
如果你的配置的物件只是暫時性的,也就是說只用在某個 function之內。強烈建議你使用auto_ptr。因為,使用了auto_ptr你就無須擔心記憶體是否被釋放掉。只要離開該function或是某個scope,記憶體肯定會被釋放。你就不用老是想著要在哪裡釋放記憶體。不用在每個return前面寫上一堆delete動作。如果你的程式是使用 goto的方式或者寫的像下面這樣…..拜託改用auto_ptr吧…
TList *myList = new TList() ; TButton *btn = new TButton(this); char *ptr = new char ; ... if(OpenFileFailed) { delete myList ; delete btn ; delete ptr ; return ; } ... if(OtherFailure) { delete myList ; delete btn ; delete ptr ; return ; } ... if(SomeThingTrue) { delete myList ; delete btn ; delete ptr ; return ; } delete myList ; delete btn ; delete ptr ; return ;如果你的程式配置了記憶體可是你也沒有用goto的方式,也沒有寫成向上面那樣,也沒有使用auto_ptr,也沒有用其它技術來釋放記憶體…. 那麼……你該死了……Memory Leak最多的一定就是你…
safepointer.h 列表:
/** * @file SAFE pointer access include file. * @author Gary W. Lee */ #ifndef __SAFEPOINTER_H__ #define __SAFEPOINTER_H__ #ifdef WINDOWS #define SP_SHOWMSG(msg) MessageBox(NULL, (msg), ,"ERROR", MB_OK) #else #define SP_SHOWMSG(msg) fprintf(stderr, "%snn", (msg)) #endif #define SAFENEW(p,t) try { n if(((p) = new t)==NULL) n { n SP_SHOWMSG("Virtual memory exhausted! Program Exit!"); n } n } catch (Exception &e) { n SP_SHOWMSG(e.Message.c_str()); n p = NULL ; n }/// 讓物件記憶體配置後檢查是否配置成功。 #define SAFEDELETE(p) if((p)) n { delete (p); p = NULL; } /// 讓物件被delete後,將其值設為NULL。並且在delet物件之前,先確定該指標不為NULL。 #define SAFEDELETE_ARRAY(p) if((p)) n { delete [] (p); p = NULL; } /// 讓物件Array被delete後,將其值設為NULL。並且在delet物件之前,先確定該指標不為NULL。 #endif // end of !__SAFEPOINTER_H__
No comments:
Post a Comment