1. 程式人生 > >C/C++知識點梳理之new/delete與malloc/free的區別

C/C++知識點梳理之new/delete與malloc/free的區別

1.就new/delete和malloc/free的本質而言(屬性):

new/delete是C++關鍵字,而malloc/free是c語言的庫函式。其次new/free在為物件開闢/釋放空間時會呼叫物件的建構函式/解構函式;而對於非內部型別malloc/free為物件動態的分配空間就不能夠滿足了。而且new/free是關鍵字,編譯器可以控制其呼叫物件的建構函式對物件成員建立時進行初始化工作,在物件消亡時呼叫解構函式進行資源的釋放工作。但對於malloc/free是函式,編譯器對其並沒有控制權,因而無法執行物件的構造和析構。

2.引數:

new在為物件分配空間操作時只無需指定記憶體塊的大小,編譯器會根據物件的型別自行計算所需分配空間的大小;而malloc在進行記憶體分配操作時指定所需分配記憶體塊的大小。
3.返回值:


new分配空間成功時會返回的是物件型別的指標,失敗new會丟擲bac_alloc異常;而malloc分配空間成功之後會返回void*,需要使用者根據所需型別進行強制型別轉換,失敗時返回空。這樣一來,我們可以看出new是malloc更加安全的操作。

4.自定義型別:

new首先會呼叫operator new函式申請充足的空間(底層通常通過malloc),然後呼叫型別的建構函式對其進行初始化操作,最後返回物件型別的指標。delete先呼叫解構函式,然後呼叫operator delete函式進行資源的釋放(底層通常呼叫free)。
malloc/free是庫函式,只是庫函式,編譯器無法控制為自定義型別呼叫物件的建構函式和解構函式。

5.記憶體區域:

malloc分配空間是在對堆上分配的,而new是在自由儲存區為物件分配空間的。(自由儲存區是C++基於new抽象出來的一種概念,凡是通過new操作符申請記憶體該記憶體成為自由儲存區)。
6.在用法上有所不同:

  • 1.malloc/free是庫函式,在使用時必須包標頭檔案;new/delete是關鍵字(運算子)在使用時不需要標頭檔案
  • 2.malloc/free和new/delete在使用上的具體區別
    mallo/free使用要點:
    malloc函式原型:void* malloc(size_t size);
    申請一塊長度為len的整型型別的記憶體,如下
    int* ptr = (int*) malloc(sizeof(int)*len);

注意:強制型別轉換,和sizeof(int);

  • 1.首先malloc的返回值型別為void*,使用者需要根據所需型別進行強制型別轉換。
  • 2.malloc並不關心資料型別,只關注所需記憶體的總子節數。
  • malloc/free使用要點
    free函式原型 void free(void* memblock);
    free沒有malloc那麼複雜?原因指標ptr的型別以及所指向空間的大小是事先知道的,free(ptr)是正確的,如果ptr為NULL,無論對p進行多少次free都是正確的;但如果ptr不為空,那麼對p進行多次free釋放程式會崩掉;當釋放掉這塊空間後,必須將這個指標賦NULL。
  • new/free的使用要點:
    對比new和malloc申請同樣長度的整型空間,就會發現new的使用會比malloc使用簡單得多:
    int* ptr_m = (int*)malloc(sizeof(int)len);
    int
    ptr_n = new int[len];
    new不要計算位元組數,只關心物件個數與物件的型別,原因是new內建了sizeof、型別轉換(原因是new其實底層用的就是malloc)、型別安全檢測。對於非內部型別的申請空間,new會呼叫自定義型別的建構函式為其進行初始化。
    注意:如果想通過new建立物件陣列,只能呼叫物件的無參建構函式或者全預設建構函式。
    不能這樣使用new:int* ptr_n = new intlen;試圖為這len個整型同時賦值為1,這種操作是不允許的。

delete釋放物件陣列時,正確方式:delete[] ptr_n;錯誤方式 delete ptr_n//這樣意味著只是放掉了整個陣列的第一個元素空間,其餘len-1個物件並沒被釋放。

  • 1.new在為物件申請空間時不需要計算單個物件的位元組大小;malloc為物件分配空間時需要手動計算單個物件的位元組數。
  • 2.返回值:new成功時為物件返回一個物件型別的指標。失敗時new會丟擲bac_alloc異常;malloc成功是返回一個void*型別的指標,使用者需要手動的根據所需型別強制型別轉換。失敗時返回一個空指標,因此使用者在使用前必須判斷malloc申請記憶體是否成功。
  • 3.new是型別安全的,malloc不是:
int* ptr_n = new float(2);//編譯能夠指出編譯錯誤
int* ptr_m = (int*)malloc(sizeof(float)*2);//編譯器無法指出錯誤

new有兩步構成:operator new 和constructor構成
operator new對應於malloc,但operator new可以過載,可以自定義記憶體分配策略,甚至不分配記憶體,甚至分配非記憶體裝置上,而malloc無能為力。
new能夠呼叫constructor,而malloc不能;delete能呼叫destructor,free不能。

  • 4.malloc/free需要庫檔案支援,而new/delete不需要

下面來看一下new/delete申請/釋放空間時編譯器會呼叫自定義型別物件時,會呼叫物件的建構函式和解構函式。

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	A(int a)
		:_a(a)
	{ }
	~A()
	{
		cout << "~A()" << endl;
	}
	void Initialization()
	{
		cout << "initialization()" << endl;
	}
	void Destroy()
	{
		cout << "destroy()" << endl;
	}
private:
	int _a;
};

void test_m_n()
{
	A* a = new A();
	delete a;
	A* b = (A*)malloc(sizeof(A));
	b->Initialization();
	b->Destroy();
	free(b);
}

類A內部實現了initialization和destroy函式實現物件的構造和析構功能,malloc/free不能呼叫構造和解構函式,必須通過呼叫成員函式initialization()和destroy()來完成物件的構造和析構功能。因此我們不能通過malloc/free完成動態物件的記憶體管理。由於內部型別沒有構造和析構過程,故在這種情況下malloc/free和new/delete是等價的,不過new會為其進行初始化工作。