我們先了解計算機中的內存在使用中被分爲下面幾部分:
內存佈局
棧:也叫堆棧,系統自動分配的空間,只要不特殊聲明,系統自動在棧上給變量和函數分配內存。棧是自頂向下增長的
堆:可使用動態內存分配的方式申請堆空間,當數據量較大時,棧空間有限,可在堆上申請空間存放;用完需要手動釋放!
常量區:用於存放程序中使用到的常量
代碼區:存放可執行代碼,在執行過程避免頻繁的讀取磁盤
作爲開發者,我們在程序中只需要管理的就是內存中的堆空間了,在c語言中我們使用一組函數來進行管理:c語言內存管理函數,那麼在c++中我們會有更好用的內存管理方式嗎?
new和delete的使用
肯定是有的,在c++中存在new和delete這兩個運算符專門用於內存管理,那麼這兩個運算符是如何使用的?
int main()
{
int* pi=new int;
int* pi1=new int(19);
int* arr=new int[10];
int i=0;
for(i=0;i<10;i++)
{
arr[i]=i;
cout<<arr[i]<<" ";
}
cout<<endl;
cout<<"*pi:"<<*pi<<" pi1:"<<*pi1<<endl;
//delete[] arr;
delete arr;
delete pi;
delete pi1;
return 0;
}
運行結果:
上面的關於new的使用:
- 爲一個類型數據在堆上分配空間 : new 類型名
- 爲一個類型數據在堆上分配空間並初始化爲給定初值:new 類型名(初值)
- 爲一個數據開闢一定個數的空間: new 類型名 [數據個數]
其中注意int* pi1=new int(19); 是開闢int類型的空間並給初值爲19,並不是開闢了19個int類型的空間。
使用完new出來的空間使用完以後就一定要記得使用delete對其分配的空間進行釋放:
- 釋放單個類型數據 :delete 類型指針名
- 釋放整個數組空間:delete[] 數組指針名
注意:對於數組空間的釋放,delete的使用稍有不同,當數組的數據類型爲基本類型時delete和delete[]都可對其進行釋放,但當數組的數據類型爲自定義類型時,delete在使用時只釋放了arr[0]的空間,那麼就不是我們想要的結果了,所以只能用dalete[] 的方式釋放。
c++相對於c語言中的內存管理函數有何優勢?
new和delete相對於c語言中的malloc、free等函數來講,new和delete的同時會調用構造和析構函數,並且加入了分配失敗的異常機制,這樣new和delete在使用起來就非常方便,有大佬模擬了這兩個運算符的內部實現,供大家學習一下:new和delete的使用
我們通過學習可以看到new和delete還是通過調用malloc和free來分配和釋放內存空間,但是更加便利的是它們會自動調用構造和析構函數。
如果數據類型爲基本類型,那麼是不需要調用構造函數和析構函數的,只有當數據類型爲自定義類型時,纔會調用構造函數和析構函數。
當開闢或釋放自定義類型的數組數據時,開闢了N個數據時,就調用了N次構造函數和N次析構函數。
new定位表達式
當頻繁的分配空間時,我們就會頻繁的調用malloc,這樣機會導致效率降低;new定位表達式則會提前分配好的空間上調用構造函數初始化,不用再次分配空間,以提高效率。
int main()
{
char* buffer=new char[1024];//內存池
size_t size=0;
Data* pd=new(buffer+size)Data(2015,2,22);//在內存池中分配實例化
size+=sizeof(Data);
Data* pd2=new(buffer+size)Data(2019,2,22);
cout<<(void*)buffer<<endl<<pd<<endl<<pd2<<endl;
pd2->~Data();
pd->~Data();
//delete buffer;
delete[] buffer;
return 0;
}
運行結果:
通過new定位表達式申請的空間實際並沒有開闢新的空間,new(指針)類型申請的地址一般是括號裏指針保存的地址,然後調用構造函數,所以無需delete釋放,如果要釋放,可以通過顯示調用析構函數的方式釋放。例:pd->~Data();
那麼如果delete pd之後會出現問題嗎?當然,我們在delete pd會將定位表達式分配給pd的那部分內存釋放,然而當你在定位表達式適用完之後釋放預先分配的空間時,那這塊空間就被重複釋放。