緒論
我成功是因?yàn)槲矣袥Q心,從不躊躇。——拿破侖?
本章是關(guān)于c++內(nèi)存管理的文章,字?jǐn)?shù)不多,內(nèi)容簡(jiǎn)單,希望對(duì)你有所幫助!!
![]()
話不多說(shuō)安全帶系好,發(fā)車(chē)?yán)?strong>(建議電腦觀看)。
附:紅色,部分為重點(diǎn)部分;藍(lán)顏色為需要記憶的部分(不是死記硬背哈,多敲);黑色加粗或者其余顏色為次重點(diǎn);黑色為描述需要
思維導(dǎo)圖:
要XMind思維導(dǎo)圖的話可以私信哈
目錄
緒論
1.C/C++內(nèi)存分布
2.c++中的內(nèi)存管理方式(new 、 delete)
3.new 和 delete 的底層
4.malloc 、free 與 new 、delete 的區(qū)別:
1.C/C++內(nèi)存分布
知識(shí)點(diǎn):
C/C++中的程序內(nèi)存分布的區(qū)域主要有:
內(nèi)核空間,棧,堆,內(nèi)存映射區(qū),靜態(tài)區(qū)(數(shù)據(jù)段),常量區(qū)(代碼段)。
細(xì)節(jié):
1.?棧又叫堆棧--非靜態(tài)局部變量/函數(shù)參數(shù)/返回值等等,棧是向下增長(zhǎng)的。
2. 內(nèi)存映射段是高效的I/O映射方式,用于裝載一個(gè)共享的動(dòng)態(tài)內(nèi)存庫(kù)。用戶可使用系統(tǒng)接口
創(chuàng)建共享共享內(nèi)存,做進(jìn)程間通信。(Linux課程如果沒(méi)學(xué)到這塊,現(xiàn)在只需要了解一下)
3. 堆用于程序運(yùn)行時(shí)動(dòng)態(tài)內(nèi)存分配,堆是可以上增長(zhǎng)的。
4. 數(shù)據(jù)段--存儲(chǔ)全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù)。
5. 代碼段--可執(zhí)行的代碼/只讀常量
如下圖:
練習(xí):
//分析下面數(shù)據(jù)在內(nèi)存的哪一個(gè)區(qū)域 int globalVar = 1; static int staticGlobalVar = 1; void Test() { static int staticVar = 1; int localVar = 1; int num1[10] = { 1, 2, 3, 4 }; char char2[] = "abcd"; const char* pChar3 = "abcd"; int* ptr1 = (int*)malloc(sizeof(int) * 4); int* ptr2 = (int*)calloc(4, sizeof(int)); int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4); free(ptr1); //此處并不需要對(duì)ptr2進(jìn)行釋放,因?yàn)槠渲赶虻目臻g可能和ptr3一樣,釋放ptr3即可 free(ptr3); }
分析如下圖:
2.c++中的內(nèi)存管理方式(new 、 delete)
知識(shí)點(diǎn):
我們?cè)贑語(yǔ)言中已經(jīng)學(xué)過(guò)如何開(kāi)辟內(nèi)存(malloc 、 calloc 、 realloc)、和釋放內(nèi)存(free)了,但是其實(shí)用起來(lái)并不太方便(在我們申請(qǐng)后還需要去判斷是否申請(qǐng)成功)
所以在c++中進(jìn)行了一定的改變創(chuàng)建了new,原理一樣也是向堆上去申請(qǐng)空間,但是此時(shí)如果未申請(qǐng)成功的話,他會(huì)直接報(bào)錯(cuò),而不是返回一個(gè)NULL(這主要是因?yàn)閏++是面向?qū)ο蟮亩鳦語(yǔ)言是面向過(guò)程的)
細(xì)節(jié):
具體使用方法(語(yǔ)法):
- 類(lèi)型 * ptr = new 類(lèi)型;(申請(qǐng)類(lèi)型大小的空間)
delete ptr; (釋放)
類(lèi)型 * ptr =? new 類(lèi)型[n] (申請(qǐng)類(lèi)型大小的n個(gè)空間)
delete[] ptr; (釋放)
-----------------------------------------------------------------------
- 對(duì)申請(qǐng)的空間進(jìn)行初始化
類(lèi)型 * ptr =?new 類(lèi)型(n) (對(duì)申請(qǐng)的內(nèi)存初始化為n)
類(lèi)型 * ptr = new 類(lèi)型[n]{a,b,c ...} (對(duì)申請(qǐng)的多個(gè)空間進(jìn)行按順序初始化為 a 、b 、c .... 不寫(xiě)則初始化為0)
c++與C語(yǔ)言的對(duì)比以及一些更加詳細(xì)的細(xì)節(jié)如下代碼的注釋中(很重要一定要細(xì)看):
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdlib.h>
int main()
{
//c:
int* ptr1 = (int*)malloc(sizeof(int));
free(ptr1);
//c++:
int* ptr2 = new int;//此時(shí)和上面的申請(qǐng)的空間是一樣的其大小也是一個(gè)整形的大小
delete ptr2;//釋放也是一樣
//c:
int* ptr3 = (int*)malloc(sizeof(int) * 10);
free(ptr3);
//c++:
int* ptr4 = new int[10];//此時(shí)和上面的申請(qǐng)的空間是一樣也是10個(gè)整形的大小
delete[] ptr4;
//c:
//malloc不會(huì)進(jìn)行初始化,我們只能另寫(xiě)一個(gè)程序進(jìn)行初始化
//c++:
//c++就能直接在申請(qǐng)空間的同時(shí)進(jìn)行初始化工作
//具體如:
int* ptr5 = new int(10);//注意這里時(shí)圓括號(hào) , 和創(chuàng)建多個(gè)對(duì)象的方括號(hào)不一樣
delete ptr5;
//對(duì)申請(qǐng)多個(gè)空間的也能進(jìn)行初始化
int* ptr6 = new int[10]{};//用中括號(hào)進(jìn)行初始化,什么都不寫(xiě)時(shí)表示申請(qǐng)的空間初始化為0
delete[] ptr6;
int* ptr7 = new int[10]{1,2,3};//部分初始化,剩下沒(méi)寫(xiě)的初始化為0
delete[] ptr7;
A* ptr8 = new A[3];//此處假如A類(lèi)型沒(méi)有默認(rèn)構(gòu)造的話是不行的,反之則可以
delete[] ptr8;
A* ptr9 = new A[3]{1,2,3};//支持隱式類(lèi)型轉(zhuǎn)換拷貝構(gòu)造后在構(gòu)造
delete[] ptr9;
A* ptr10 = new A[3]{ A(1),A(2),A(3) };//此時(shí)就沒(méi)有隱式類(lèi)型轉(zhuǎn)換了,直接進(jìn)行構(gòu)造
delete[] ptr10;
return 0;
}
練習(xí):
創(chuàng)建節(jié)點(diǎn)ListCode:
class ListCode
{
public:
ListCode(int val = 0)
:val(val)
,next(nullptr)
{
}
private:
int val;
struct ListCode* next;
};
int main()
{
//在C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)中我們可能還需要去寫(xiě)一個(gè)ListCode()的創(chuàng)建節(jié)點(diǎn)的函數(shù)
//但此時(shí)我們可以直接寫(xiě)成如下模樣
ListCode* n1 = new ListCode(1);//還進(jìn)行了構(gòu)造
ListCode* n2 = new ListCode(2);
return 0;
}
3.new 和 delete 的底層原理
知識(shí)點(diǎn):
new 和 delete 他們的底層原理其實(shí)也是需要去調(diào)用了 malloc 和 free 的 不過(guò)因?yàn)槊嫦驅(qū)ο蟮脑?,他們一般來(lái)說(shuō)都是直接拋異常 , 所以在使用malloc 和 free 之前他們需要先去調(diào)用一個(gè)全局函數(shù) 分別是 operator new 和 operator delete?
異常錯(cuò)誤信息(此時(shí)申請(qǐng)不到空間了):
細(xì)節(jié):
- operator new與operator delete函數(shù):? ? new和delete是用戶進(jìn)行動(dòng)態(tài)內(nèi)存申請(qǐng)和釋放的操作符,operator new 和operator delete是系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來(lái)申請(qǐng)空間,delete在底層通過(guò)operator delete全局函數(shù)來(lái)釋放空間。而其實(shí)operator new 和 operator delete 他們都會(huì)去調(diào)用 malloc 和 free 并且 如果失敗時(shí) 就會(huì)再自身里面識(shí)別并且報(bào)錯(cuò)錯(cuò)誤信息
- 針對(duì)自定義類(lèi)時(shí) : new 和 delete 他們其實(shí)還會(huì)去調(diào)用 構(gòu)造函數(shù) 和 析構(gòu)函數(shù) , 來(lái)進(jìn)行對(duì)其中的數(shù)據(jù)的初始化和銷(xiāo)毀
- new 調(diào)用的順序?yàn)椋簅perator new -> 構(gòu)造函數(shù) 、 delete 調(diào)用順序?yàn)?: 析構(gòu)函數(shù) -> operator delete? , 并且注意他們的順序是不能改變的 , 因?yàn)?析構(gòu)函數(shù)需要先把對(duì)象中申請(qǐng)的空間給釋放了 , 然后才能把這個(gè)new借的空間釋放掉(反過(guò)來(lái)先把new的空間釋放的話就找不到對(duì)象已經(jīng)對(duì)象中申請(qǐng)的空間了); 同理 對(duì)于new 來(lái)說(shuō)得先為 對(duì)象 申請(qǐng)空間后(創(chuàng)建對(duì)象)?才能在對(duì)象的 空間上申請(qǐng)其他的空間?
![]()
- 綜上所述得出下圖:
![]()
- 對(duì)于 new int[ ] , delete[] ptr? 他們會(huì)先調(diào)用 operator new[] 然后再調(diào)用n次operator new 和n次構(gòu)造函數(shù), delete 類(lèi)似
- 附:捕獲異常的方法
int* ptr = nullptr; try { do { ptr = new int[1024 * 1024]; cout << ptr << endl; } while (ptr); } catch (const exception& e ) { cout << e.what() << endl; } // try //{} //catch(const exception& e) //{ // cout <<e.what()<<endl; //}
附:定位new
功能:定位new表達(dá)式是在已分配的原始內(nèi)存空間中調(diào)用構(gòu)造函數(shù)初始化一個(gè)對(duì)象
使用格式 :?new (place_address) type或者new (place_address) type(initializer-list)
place_address必須是一個(gè)指針,initializer-list是類(lèi)型的初始化列表用處:可以用于池化技術(shù)處,也就是操作系統(tǒng)會(huì)先創(chuàng)建一個(gè)內(nèi)存池,里面已經(jīng)提前申請(qǐng)了一定的空間,此時(shí)我們就能更方便的去申請(qǐng)空間,而不是需要了去申請(qǐng),需要了去申請(qǐng),這里申請(qǐng)到的空間自然就不會(huì)進(jìn)行構(gòu)造函數(shù)初始化,所以我們就能使用定位new的方式對(duì)已申請(qǐng)的空間進(jìn)行初始化
具體使用方法:
int main() { // p1現(xiàn)在指向的只不過(guò)是與A對(duì)象相同大小的一段空間,還不能算是一個(gè)對(duì)象,因?yàn)闃?gòu)造函數(shù)沒(méi)有執(zhí)行 A* p1 = (A*)malloc(sizeof(A)); new(p1)A; // 注意:如果A類(lèi)的構(gòu)造函數(shù)有參數(shù)時(shí),此處需要傳參 p1->~A(); free(p1); return 0; }
4.malloc 、free 與 new 、delete 的區(qū)別:
知識(shí)點(diǎn):
- 首先new是基于c++面向?qū)ο蟮那闆r而創(chuàng)建的,所以在我們申請(qǐng)不到空間時(shí)是進(jìn)行拋出異常,而malloc則是面向過(guò)程的,當(dāng)申請(qǐng)不到空間時(shí)返回一個(gè)空指針
- 其次new要比malloc寫(xiě)起來(lái)更加的快捷,他不用再進(jìn)行類(lèi)型大小的計(jì)算,以及有著更加方便的初始方式
- 最后也是最重要的部分,new 和 delete 是針對(duì)自定義類(lèi)型而創(chuàng)建的他們能很好的去進(jìn)行初始化自定義類(lèi)型,并且在申請(qǐng)、釋放空間的過(guò)程還進(jìn)行了構(gòu)造和析構(gòu)函數(shù)的調(diào)用
- 附:malloc和free是函數(shù),new和delete是操作符、malloc的返回值為void*, 在使用時(shí)必須強(qiáng)轉(zhuǎn)、malloc申請(qǐng)空間失敗時(shí),返回的是NULL,因此使用時(shí)必須判空
?
本章完。預(yù)知后事如何,暫聽(tīng)下回分解。
如果有任何問(wèn)題歡迎討論哈!
如果覺(jué)得這篇文章對(duì)你有所幫助的話點(diǎn)點(diǎn)贊吧!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-478239.html
持續(xù)更新大量C++細(xì)致內(nèi)容,早關(guān)注不迷路。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-478239.html
到了這里,關(guān)于C++如何進(jìn)行內(nèi)存管理 (new、delete)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!