12、關於動態記憶體分配

2020-08-12 11:22:32

文編寫參考狄泰軟體學院唐佐林老師的視訊課程,如有錯誤之處,歡迎指正。

一、c++中記憶體申請與c語言記憶體申請的異同

1、對於new關鍵字和malloc函數

new關鍵字的功能類似於c語言中的malloc,它們都是從堆空間中申請一段記憶體。下面 下麪幾點是兩者之間的異同點:

  1. new是c++中的關鍵字,而malloc是c庫提供的函數,有些c編譯器可能是沒有這個庫的,那麼就會導致不能申請動態空間
  2. new是以具體型別爲單位進行記憶體分配,而malloc是以位元組爲單位進行記憶體分配。
  3. new在申請單個型別變數時可以進行初始化,而malloc不可以,calloc函數雖然是將空間裡的值初始化爲0,但是並不是初始化爲使用者希望的值,所以還不是真正意義上的初始化。
  4. new能夠觸發建構函式的呼叫,malloc僅分配需要的記憶體空間

在c++中在堆空間爲物件申請空間時,是需要呼叫建構函式的,而這個必須通過new關鍵字來實現,因爲採用malloc函數只是說從堆空間中申請一段記憶體,但是並不會呼叫建構函式,也就是說生成的物件是不合法的.

  1. 物件的建立只能使用用new,malloc函數不適合物件導向開發

2、對於delete關鍵字和free函數

  1. delete在所有c++編譯器都被支援
  2. free在沒有c庫的時候不能夠被呼叫,而某些開發系統中是沒有c庫的
  3. delete能夠觸發解構函式的呼叫,free僅僅歸還之前分配的記憶體空間
  4. 物件的銷燬只能夠用delete,free不適合物件導向開發
  5. new是通過delete釋放空間的,而malloc是以free來釋放空間的。對此要特別注意的是:
    (1)對單個型別變數的釋放和對陣列的釋放在形式上是有區別的,對陣列空間進行釋放時一定要加上[]。
    (2)用new就一定用delete,用malloc就用free,不能夠混合使用,原因如下:

因爲這樣雖然可以通過編譯,但是這是會帶來問題的,假設用new爲物件在對空間中申請了一段記憶體,那麼此時就會出發建構函式的呼叫,從而完成物件的構造,當使用delete關鍵字來歸還空間時,首先會呼叫解構函式,進行物件的銷燬,然後再歸還空間,但是當使用free函數來歸還空間,這時是不會自動呼叫解構函式的,它完成的工作僅僅是歸還堆空間,那麼如果此時物件裏面的成員變數也是從堆空間裏面申請的,那麼這時就會造成記憶體泄露。同樣地,我們不能夠用delete用mallocd申請的堆空間,有可能通過編譯,但是同樣的也會帶來問題,有可能這個問題會暫時沒出現,因爲用malloc函數申請堆空間時並沒有生成一個合法的物件,而用delete關鍵字就會呼叫解構函式,去呼叫一個不合法物件的解構函式是很可能會出現問題的。

二、例程理解

例程1:

#include<iostream>
using namespace std;
int main()
{
	int* p1=new int(5);
	char* p2=new char('a');
	float* p4=new float(2.1f);
	cout<<"*p1="<<*p1<<endl;
	cout<<"*p2="<<*p2<<endl;
	cout<<"*p4="<<*p4<<endl;

	delete p1;
	delete p2;
	delete p4;	
	int* p3=new int[10];
	for(int i=0;i<10;i++)
	{
		p3[i]=i+1;
		cout<<"p3"<<"["<<i<<"]="<<p3[i]<<endl;
	}
	delete[] p3; 
	return 0;
}

在这里插入图片描述
例程2:

#include <iostream>
#include <string>
#include <cstdlib>//C標準通用實用庫,此檔頭定義了幾個通用功能,包括動態記憶體管理,亂數生成,與環境的通訊,整數算術,搜尋,排序和轉換。

using namespace std;

class Test
{
    int* mp;
public:
    Test()
    {
        cout << "Test::Test()" << endl;
        mp = new int(100);
        cout << *mp << endl;
    }
    ~Test()
    {
        delete mp;//歸還記憶體空間

        cout << "~Test::Test()" << endl;
    }
};

int main()
{
    Test* pn = new Test;//用c++的方式,申請空間的同時會呼叫建構函式,完成物件的構造
    Test* pm = (Test*)malloc(sizeof(Test));//用c語言的方式,只負責申請空間,不負責物件的構造,因此生成的物件不合法
    
    delete pn;//會先呼叫解構函式銷燬物件,然後歸還空間
    free(pm);//只負責歸還空間,而不負責銷燬物件
    
    return 0;
}

在这里插入图片描述
分析:此處只調用了一個建構函式和解構函式,因此證明了此文開頭的一些結論,這裏也可修改程式驗證其餘的結論,這裏就不一一演示了。