C/C++內存管理---new和delete

一、new/delete 簡介

C 語言中的動態內存管理方式有malloc、calloc、realloc 和 free,但是 malloc 和 free 是函數,new 和 delete 是 C++ 用於管理堆內存的兩個運算符

二、new/delete實現原理及操作

1.內置類型操作
void Test1()
{
	int* p1 = new int;//動態申請1個int類型的空間
	int* p2 = new int(10);//動態申請1個int類型的空間,並初始化爲10
	int* p3 = new int[10];//動態申請10個int類型的空間(類型爲int[10])
	int* p4 = new int[10]{ 1,2,3,4,5,6,7,8,9,0 };//動態申請10個int類型的空間。並初始化爲{1~0}

	delete p1;
	delete p2;
	delete[] p3;
	delete[] p4;
}
  • 申請內置類型空間時,new和malloc,delete和free基本類似。
  • 申請和釋放單個內存,用new和delete操作符,申請和釋放連續的空間,用new[]和delete[]操作符。
  • new在申請失敗時會拋出異常,malloc會返回NULL

如果new和delete沒有匹配使用,產生後果?

void Test2()
{
	int* p1 = new int;
	int* p2 = new int[10];
	int* p3 = new int[10];
	delete[] p1;
	delete p2;
	free(p3);

	//...
}

結論:如果申請的是內置類型的空間,不會產生任何後果

2.自定義類型操作
class Test
{
public:
	Test()
		:_data(10)
		,_p(new int)
	{
		cout << "Test():" << this << endl;
	}
	~Test()
	{
		delete _p;
		cout << "~Test():" << this << endl;
	}
private:
	int _data;
	int* _p;
};
void Test3()
{
	Test* p1 = new Test;//申請單個Test類型的對象
	delete p1;
	cout << endl;
	Test* p2 = new Test[10];//申請10個Test類型的對象
	delete[] p2;

	Test* p3 = (Test*)malloc(sizeof(Test)); //申請單個Test類型的空間
	//malloc申請空間時不會調用構造函數--申請的是與對象大小相同的一塊內存空間,不能將該塊內存空間看成一個對象
	free(p3);
	Test* p4 = (Test*)malloc(sizeof(Test) * 10);//申請10個Test類型的空間
	free(p4);
}

new的原理

  1. 調用operator new函數申請空間,operator new函數實際通過malloc來申請空間,空間申請成功直接返回,申請失敗時檢測是否有空間不足應對措施,有則繼續申請,沒有就拋出異常。
  2. 在申請的空間上調用構造函數,完成對象的構造

delete的原理

  1. 在空間上調用析構函數,完成對象中資源的清理工作
  2. 調用operator delete函數釋放對象的空間,operator delete函數本質是通過free來釋放空間的。

new T[N]的原理

  1. 調用operator new[]函數,在operator new[]中實際調用operator new函數,而operator new函數實際通過malloc循環申請空間,完成N個對象空間的申請。
  2. 在申請的空間上調用N次構造函數

delete[ ]的原理

  1. 在釋放的對象空間上調用N次析構函數,完成N個對象中資源的清理。
  2. 調用==operator delete[]==釋放空間,實際在operator delete[ ]中調用operator delete,而operator delete函數實際通過free來釋放空間。

如果new和delete沒有匹配使用,產生後果?

void Test4()
{
	Test* p1 = new Test;
	free(p1);//不報錯

	Test* p2 = new Test[10];
	delete p2;//報錯

	Test* p3 = new Test;
	delete[] p3;//報錯 崩潰
}

結論:不管是new還是delete,只要涉及到[ ],必然會崩潰。

三、定位new表達式(placement-new)

含義:定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象。
使用格式:new (place_address) type或者new (place_address) type(initializer-list)
place_address必須是一個指針,initializer-list是類型的初始化列表。
使用場景:定位new表達式在實際中一般是配合內存池使用。因爲內存池分配出的內存沒有初始化,所以如果是自定義類型的對象,需要使用new的定義表達式進行顯示調構造函數進行初始化。

void Test6()
{
	// p1現在指向的只不過是與Test對象相同大小的一段空間,還不能算是一個對象,因爲構造函數沒有執行
	Test* p1 = (Test*)malloc(sizeof(Test));
	new(p1) Test; //如果Test類的構造函數有參數時,此處需要傳參
}

總結

malloc/free和new/delete的相同和不同
malloc/free和new/delete的共同點是:都是從堆上申請空間,並且需要用戶手動釋放。

不同的地方是:

  1. malloc和free是函數,new和delete是操作符。
  2. malloc申請的空間不會初始化,new可以初始化。
  3. malloc申請空間時,需要手動計算空間大小並傳遞,new只需在其後跟上空間的類型即可。
  4. malloc的返回值爲void*, 在使用時必須強轉,new不需要,因爲new後跟的是空間的類型。
  5. malloc申請空間失敗時,返回的是NULL,因此使用時必須判空,new不需要,但是new需要捕獲異常。
  6. 申請自定義類型對象時,malloc/free只會開闢空間,不會調用構造函數與析構函數,而new在申請空間後會調用構造函數完成對象的初始化,delete在釋放空間前會調用析構函數完成空間中資源的清理。
  7. malloc申請的空間一定在堆上,但new不一定。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章