C++ 中 malloc/free與 new/delete區別
new/delete 通常來說是操作符,就是"+","-"一樣,malloc/free 是 C++/C 語言的標準庫函式 —— 本質區別。本文主要從以下5各方面比較、分析 malloc/free,new/delete 的區別 。 1.自動地分配所需空間。2.自動返回指標型別。3.初始化不同。4.原始碼實現不同。5.常見問題為什麼有了new不剔除malloc。
【正文】
本質區別
new/delete 通常來說是操作符,就是"+","-"一樣。 malloc/free 是 C++/C 語言的標準庫函式 ——本質區別;
操作物件範圍不同
new/delete 是 C++ 裡才有的,而 new/delete 與 malloc/free 一個顯著的區別在於,new 是建造一個物件,並呼叫物件的建構函式來初始化物件,其實在所有的 new 操作過程中,總是分為兩步的:第一步是申請記憶體,第二步則是呼叫建構函式初始化物件(也有文章指出,第三步是返回指標所指向物件的型別和地址)。同樣,在呼叫 delete 的時候,需要先呼叫解構函式,然後在銷燬堆記憶體。換言之 , 對於非內部資料型別的物件而言,光用 malloc/free 無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行解構函式。由於 malloc/free 是庫函式而不是運算子,不在編譯器控制權限之內,不能夠把執行建構函式和解構函式的任務強加於 malloc/free 。如果用 free 釋放“ new 建立的動態物件”,那麼該物件因無法執行解構函式而可能導致程式出錯。如果用 delete 釋放“ malloc 申請的動態記憶體”,理論上講程式不會出錯,但是該程式的可讀性很差。所以 new/delete 必須配對使用, malloc/free 也一樣。 C++ 預設的 new/delete 操作符內部,其實也呼叫了 malloc/free 這兩個函式;
使用方法上的區別
1. new能夠按照變數型別自動地分配所需空間長度,不必使用巨集sizeof。
2. new能夠自動返回正確的指標型別。
3. 必須時,new能將單個變數初始化。
用例闡述
malloc
用 malloc 申請一塊長度為length 的整數型別的記憶體,程式如下:
int *p = (int *) malloc ( sizeof(int) * length);
我們應當把注意力集中在兩個要素上:“型別轉換”和“sizeof”。
void * malloc(size_t size);
1、malloc 返回值的型別是 void *,所以在呼叫 malloc 時要顯式地進行型別轉換,將 void * 轉換成所需要的指標型別。
2、malloc 函式本身並不識別要申請的記憶體是什麼型別,它只關心記憶體的總位元組數。
free
void free( void * memblock );
為什麼free 函式不象malloc 函式那樣複雜呢?這是因為指標p 的型別以及它所指的記憶體的容量事先都是知道的,語句free(p)能正確地釋放記憶體。如果p 是NULL 指標,那麼free對p 無論操作多少次都不會出問題。如果p 不是NULL 指標,那麼free 對p連續操作兩次就會導致程式執行錯誤。(懸浮指標和空指標的區別就在這裡)
new/delete
運算子 new 使用起來要比函式 malloc 簡單得多,例如:
int *p1 = (int *)malloc(sizeof(int) * length);
int *p2 = new int[length];
這是因為 new 內建了sizeof、型別轉換和型別安全檢查功能。對於非內部資料型別的物件而言,new 在建立動態物件的同時完成了初始化工作。如果物件有多個建構函式,那麼new 的語句也可以有多種形式。
如果用new 建立物件陣列,那麼只能使用物件的無引數建構函式。例如
Obj *objects = new Obj[100]; // 建立100 個動態物件
不能寫成
Obj *objects = new Obj[100](1);// 建立100 個動態物件的同時賦初值1
在用delete 釋放物件陣列時,留意不要丟了符號‘[ ]’。例如
delete []objects; // 正確的用法
delete objects; // 錯誤的用法
後者相當於delete objects[0],漏掉了另外99 個物件。
malloc/free 與 new/delete共同點
1 都必須配對使用,這裡的配對使用,可不能理解為一個 new/malloc 就對應一個 delete/free ,而是指在作用域內,new/malloc 所申請的記憶體,必須被有效釋放,否則將會導致記憶體洩露,至於記憶體洩露的檢查方法,我們推薦的工具是大家眾所周知的 Bounds Checker;
2 都是申請記憶體,釋放記憶體,free和delete可以釋放NULL指標。
既然new/delete的功能完全覆蓋了malloc /free,為什麼C++還保留malloc/free呢?
對於非內部資料型別物件(如類物件)而言,只用malloc/free 無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行解構函式。
由於,malloc/free是庫函式而不是運算子,不在編譯器控制權限之內,也就不能執行建構函式和解構函式,不能夠把執行建構函式和解構函式的任務強加於malloc/free。
所以,若要強求使用malloc/free庫函式實現非內部資料型別物件的記憶體管理,在malloc()後要有一個類物件的初始化來承擔建構函式的功能,同時,在free之前也要有一個消除函式來充當解構函式的功能,當然這是很不方便,也是不提倡的。
因此,C++語言需要一個能完成動態記憶體分配和初始化工作的運算子new,以及一個能完成清理與釋放記憶體工作的運算子delete。new/delete不是庫函式,而是運算子。
而對於內部資料型別,由於內部資料型別的物件沒有建構函式與解構函式的過程,對他們來說,malloc/free與new/delete是等價的。
或許你會問,既然new/delete的功能完全可以實現malloc/free的功能,為什麼C++中不把malloc/free淘汰掉呢,這可能涉及到一個相容性問題,C++程式要經常呼叫C函式,而C語言中只能用malloc/free來管理記憶體。