1. 程式人生 > >【轉載】C++ free與delete區別

【轉載】C++ free與delete區別

free函式是由C語言繼承而來的,是和malloc配對的,而不能和new配對。
free釋放記憶體的和delete可以說是兩套程式碼,它們的邏輯不同,不能混用。用new申請的就要用delete翻譯,用malloc申請的就要用free釋放。
順便說一下它們還有一個區別, free 只是告訴作業系統回收記憶體,而delete會先呼叫類的解構函式,然後才告訴作業系統回收記憶體。
下面是收藏的一個帖子:
	我又一個物件類,裡面有一個指標連結串列,動態分配空間,在析構的時候釋放。開始對物件進行new操作,但是執行delete物件操作的時候出錯,提示在析構的時候記憶體有問題。可是這時候成員一個位元的記憶體都沒有分配啊。所以析構的時候應該什麼記憶體操作都不執行。
更奇怪的是採用free()函式就可以釋放這種物件,但是記憶體卻不見減少,整個程式記憶體佔用節節升高?這是為什麼?
. delete呼叫destructor
   free沒有
在delete內部仍呼叫了free
你在解構函式當中沒有正確的釋放你申請的記憶體,比如,這個物件當中有一個指標,是採用動態申請記憶體的,在建構函式當中應該把它的值設定為NULL,然後在某個方法當中會申請記憶體,是採用new方法進行申請的,在析構函當中,應該先判斷該指標是否為空,如果不為空,則使用delete釋放記憶體,然後再把該指標設定為NULL。這樣就可以了,如果你在外面是採用new申請這個物件,則在使用完成後使用delete釋放就可以了。
補充一點:
new和malloc雖然都是申請記憶體,但申請的位置不同,new的記憶體從free store分配,而malloc的記憶體從heap分配(詳情請看ISO14882的記憶體管理部分),free store和heap很相似,都是動態記憶體,但是位置不同,這就是為什麼new出來的記憶體不能通過free來釋放的原因。不過微軟編譯器並沒有很好的執行標準,很有可能把free store和heap混淆了,因此,free有時也可以。
再補充一點:
delete時候不需要檢查NULL
如果TYPE *p = new TYPE[n]  那麼就要 delete[] p
建議用new~~速度比malloc快,new是運算子,malloc是函式。
如果要建立指定空間大小就用malloc。
malloc和free(及其變體)會產生問題的原因在於它們太簡單:他們不知道建構函式和解構函式。

假設用兩種方法給一個包含10個string物件的陣列分配空間,一個用malloc,另一個用new:

   

string *stringarray1 =
static_cast<string*>(malloc(10 * sizeof(string)));

string *stringarray2 = new string[10];

其結果是,stringarray1確實指向的是可以容納10個string物件的足夠空間,但記憶體裡並沒有建立這些物件。而且,如果你不從這種晦澀的語法怪圈(詳見條款m4和m8的描述)裡跳出來的話,你沒有辦法來初始化數組裡的物件。換句話說,stringarray1其實一點用也沒有。相反,stringarray2指向的是一個包含10個完全構造好的string物件的陣列,每個物件可以在任何讀取string的操作裡安全使用。

假設你想了個怪招對stringarray1數組裡的物件進行了初始化,那麼在你後面的程式裡你一定會這麼做:


free(stringarray1);
delete [] stringarray2;// 參見條款5:這裡為什麼要加上個"[]"

呼叫free將會釋放stringarray1指向的記憶體,但記憶體裡的string物件不會呼叫解構函式。如果string物件象一般情況那樣,自己已經分配了記憶體,那這些記憶體將會全部丟失。相反,當對stringarray2呼叫delete時,數組裡的每個物件都會在記憶體釋放前呼叫解構函式。

既然new和delete可以這麼有效地與建構函式和解構函式互動,選用它們是顯然的。

把new和delete與malloc和free混在一起用也是個壞想法。對一個用new獲取來的指標呼叫free,或者對一個用malloc獲取來的指標呼叫delete,其後果是不可預測的。大家都知道“不可預測”的意思:它可能在開發階段工作良好,在測試階段工作良好,但也可能會最後在你最重要的客戶的臉上爆炸。

new/delete和malloc/free的不相容性常常會導致一些嚴重的複雜性問題。舉個例子,<string.h>裡通常有個strdup函式,它得到一個char*字串然後返回其拷貝:


char * strdup(const char *ps);	// 返回ps所指的拷貝
在有些地方,c和c++用的是同一個strdup版本,所以函式內部是用malloc分配記憶體。這樣的話,一些不知情的c++程式設計師會在呼叫strdup後忽視了必須對strdup返回的指標進行free操作。為了防止這一情況,有些地方會專門為c++重寫strdup,並在函式內部呼叫了new,這就要求其呼叫者記得最後用delete。你可以想象,這會導致多麼嚴重的移植性問題,因為程式碼中strdup以不同的形式在不同的地方之間顛來倒去。

c++程式設計師和c程式設計師一樣對程式碼重用十分感興趣。大家都知道,有大量基於malloc和free寫成的程式碼構成的c庫都非常值得重用。在利用這些庫時,最好是你不用負責去free掉由庫自己malloc的記憶體,並且/或者,你不用去malloc庫自己會free掉的記憶體,這樣就太好了。其實,在c++程式裡使用malloc和free沒有錯,只要保證用malloc得到的指標用free,或者用new得到的指標最後用delete來操作就可以了。千萬別馬虎地把new和free或malloc和delete混起來用,那隻會自找麻煩。

既然malloc和free對建構函式和解構函式一無所知,把malloc/free和new/delete混起來用又象嘈雜擁擠的晚會那樣難以控制,那麼,你最好就什麼時候都一心一意地使用new和delete吧。
malloc與free是C++/C語言的標準庫函式,new/delete是C++的運算子。它們都可用於申請動態記憶體和釋放記憶體。
對於非內部資料型別的物件而言,光用maloc/free無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行解構函式。由於malloc/free是庫函式而不是運算子,不在編譯器控制權限之內,不能夠把執行建構函式和解構函式的任務強加於malloc/free。因此C++語言需要一個能完成動態記憶體分配和初始化工作的運算子new,以及一個能完成清理與釋放記憶體工作的運算子delete。注意new/delete不是庫函式。