1. 程式人生 > >new和delete,malloc和free 轉自http://www.kuqin.com/effectivec2e/ch01a.htm

new和delete,malloc和free 轉自http://www.kuqin.com/effectivec2e/ch01a.htm

條款3:儘量用new和delete而不用malloc和free

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吧。