動態記憶體開闢:new/delete,malloc/free區別與聯絡

本部落格主要說明new/delete,malloc/free的區別與聯絡,如下:

1.malloc/free為C的標準庫函式,函式原型為:

void* malloc(size_t size)//引數代表位元組個數
void free(void* pointer)//引數代表記憶體地址

new、delete則為C 的操作運算子,它呼叫的分別為賦值運算子過載operator new()和operator delete();

2.在使用上,malloc/free如下:

void func()
{
//開闢一個空間
int* p1=(int*)malloc(sizeof(int));
if(p1==NULL)
{
exit(1);
}
free(p1);
//開闢多個空間
int*p2=(int*)malloc(sizeof(int)*4);
if(p2==NULL)
{
exit(1);
}
free(p2);
}

用malloc分別開闢了1個和4個整型大小的空間和並free釋放它們;

new/delete如下:

void func()
{
//開闢一個空間
int* p1=new int(1);
delete p1;
//開闢多個空間
int*p2=new int[4];
delete []p2;
}

由此可知:

  (1)malloc開闢空間型別大小需手動計算,new是由編譯器自己計算;

  (2)malloc返回型別為void*,必須強制型別轉換對應型別指標,new則直接返回對應型別指標;

  (3)malloc開闢記憶體時返回記憶體地址要檢查判空,因為若它可能開闢失敗會返回NULL;new則不用判斷,因為記憶體分配失敗時,它會丟擲異常bac_alloc,可以使用異常機制;

  (4)無論釋放幾個空間大小,free只傳遞指標,多個物件時delete需加[](原因在第3);

3.malloc/free為函式只是開闢空間並釋放,new/delete則不僅會開闢空間,並呼叫建構函式和解構函式進行初始化和清理,如下為new/delete、new[]/delete[]實現機制:

而new[]/delete[]則為:

即過程如上,在開闢大小會多開闢四個位元組,用於存放物件的個數,在返回地址時則會向後偏移4個位元組,而在delete時則會檢視記憶體上物件個數,從而根據個數count確定呼叫幾次解構函式,從而完全清理所有物件佔用記憶體。

所以解釋2原因:對於內建型別若new[]但用delete釋放時,沒有影響,但若是自定義型別如類時,若釋放使用 delete

時,這時則會只呼叫一次解構函式,只析構了一個物件,剩下的物件都沒有被清理。

4.由上圖還可以看出new/delete底層是基於malloc/free來實現的,而malloc/free不能基於new/delete實現;

5.因為new/delete是操作符,它呼叫operator new / operator delete,它們可以被過載,在標準庫裡它有8個過載版本;而malloc/free不可以過載;

6.對於malloc分配記憶體後,若在使用過程中記憶體分配不夠或太多,這時可以使用realloc函式對其進行擴充或縮小,但是new分配好的記憶體不能這樣被直觀簡單的改變;

7.對於new/delete若記憶體分配失敗,使用者可以指定處理函式或重新制定分配器(new_handler(可以在此處進行擴充套件)),malloc/free使用者是不可以處理的。

8.最後一點對於new/delete與malloc/free申請記憶體位置說明,malloc我們知道它是在堆上分配記憶體的,但new其實不能說是在堆上,C 中,對new申請記憶體位置有一個抽象概念,它為自由儲存區,它可以在堆上,也可以在靜態儲存區上分配,這主要取決於operator new實現細節,取決與它在哪裡為物件分配空間。

所以有一些說法:new在堆上分配記憶體,可以說是不太精確的。(以上則為我總結的new/delete與malloc/free基本區別聯絡)