C++自制心得——?jiǎng)討B(tài)內(nèi)存管理
1. new與delete
我們來回顧一下C語言的內(nèi)存管理函數(shù)
顯然,malloc全家桶的缺點(diǎn)很明顯,又要強(qiáng)轉(zhuǎn),還要手動(dòng)計(jì)算申請(qǐng)空間大小,而且更糟的是,它們不適配自定義類型
如果我們用malloc開空間,其中的自定義類型是無法初始化的,因?yàn)閙alloc根本不認(rèn)識(shí)構(gòu)造函數(shù),在這種情況下,malloc完全沒法用,必須用一種新方式申請(qǐng)內(nèi)存
free函數(shù)雖然寫起來簡(jiǎn)單,但是它也不能很好的適配自定義類型
幸好析構(gòu)函數(shù)可以直接調(diào)用,不然這個(gè)對(duì)象s很難釋放
正因原裝函數(shù)過于臃腫,不支持自定義類型,所以C++提供了新的內(nèi)存管理方式,也就是new與delete操作符

new與delete的使用方法如下:
1. 沿襲C語言的傳統(tǒng),申請(qǐng)的空間需要用對(duì)應(yīng)指針變量維護(hù)
2. 申請(qǐng)空間分為單體申請(qǐng)與群體申請(qǐng),釋放空間同理
3. 申請(qǐng)多個(gè)對(duì)象時(shí),其初始化邏輯沿襲數(shù)組

4. 請(qǐng)確保對(duì)象的申請(qǐng)與釋放由對(duì)應(yīng)的函數(shù)完成,否則視為未定義行為
用malloc全家桶申請(qǐng)的空間請(qǐng)用free釋放,用new申請(qǐng)的空間請(qǐng)用delete釋放,用new[]申請(qǐng)的空間請(qǐng)用delete[]釋放,如果不這么做,出現(xiàn)什么稀奇古怪的錯(cuò)誤都是正常的
5. new與delete在申請(qǐng)或釋放空間時(shí)會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù)或析構(gòu)函數(shù)
以順序表舉例

6. new失敗后不會(huì)返回nullptr而是拋異常
2.?new和delete的底層機(jī)制
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ù)來申請(qǐng)空間,delete在底層通過operator delete全局函數(shù)來釋放空間。(這兩個(gè)函數(shù)也分單體群體)
下面是某大佬從編譯器里扒出來的operator new&delete源碼
(我也不知道下面的函數(shù)是怎么運(yùn)作的)
好吧,雖然看不懂代碼在干什么,不過malloc和free我們還是認(rèn)識(shí)的,顯然operator new和operator delete(這兩函數(shù)不是new與delete的重載函數(shù),我也不知道為什么設(shè)計(jì)人員要這么命名)是C的內(nèi)存管理函數(shù)的封裝形式
你也可以顯式調(diào)用這兩個(gè)函數(shù)(你為什么要這么做)
用法與malloc和free基本保持一致,不過申請(qǐng)失敗不會(huì)返回nullptr而是拋異常

new & delete自動(dòng)調(diào)用構(gòu)造或析構(gòu)的功能在operator new & delete外實(shí)現(xiàn),所以此處的s1,s2并未初始化

異常是C++引入的新錯(cuò)誤處理機(jī)制,大大簡(jiǎn)化了錯(cuò)誤處理的邏輯
這就是一個(gè)簡(jiǎn)單的異常處理程序,出現(xiàn)異常就會(huì)輸出異常信息

在try代碼塊中執(zhí)行的代碼一旦出現(xiàn)異常就會(huì)引起執(zhí)行流跳躍,直接跳轉(zhuǎn)到catch代碼塊,不會(huì)執(zhí)行剩下的指令,這點(diǎn)與goto頗為相似。如果異常語句不在try代碼塊中或者沒有寫異常回收機(jī)制,程序會(huì)掛掉
(徹底理解異常需要繼承多態(tài)前置,本專欄只給出基本寫法)

現(xiàn)在我們可以總結(jié)new與delete的工作原理了
1. 對(duì)于內(nèi)置類型
new和malloc,delete和free基本類似,不同的地方是: new/delete申請(qǐng)和釋放的是單個(gè)元素的空間,new[]和delete[]申請(qǐng)的是連續(xù)空間,而且new在申請(qǐng)空間失敗時(shí)會(huì)拋異常,malloc會(huì)返回nullptr。
2. 對(duì)于自定義類型
new的原理?
1. 調(diào)用operator new函數(shù)申請(qǐng)空間?
2. 在申請(qǐng)的空間上執(zhí)行構(gòu)造函數(shù),完成對(duì)象的構(gòu)造?
delete的原理?
1. 在空間上執(zhí)行析構(gòu)函數(shù),完成對(duì)象中資源的清理工作?
2. 調(diào)用operator delete函數(shù)釋放對(duì)象的空間?
new Type[N]的原理?
1. 調(diào)用operator new[]函數(shù),在operator new[]中實(shí)際調(diào)用operator new函數(shù)完成N個(gè)對(duì)象空間的申請(qǐng)?
2. 在申請(qǐng)的空間上執(zhí)行N次構(gòu)造函數(shù)?
delete[]的原理?
1. 在釋放的對(duì)象空間上執(zhí)行N次析構(gòu)函數(shù),完成N個(gè)對(duì)象中資源的清理?
2. 調(diào)用operator delete[]釋放空間,實(shí)際在operator delete[]中調(diào)用operator delete來釋放空間
3. 定位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是類型的初始化列表
借助于定位new,我們可以實(shí)現(xiàn)構(gòu)造函數(shù)的顯式調(diào)用
一般情況下,定位new沒有使用必要,在實(shí)際中一般是配合內(nèi)存池使用。因?yàn)閮?nèi)存池分配出的內(nèi)存沒有初始化,所以如果是自定義類型的對(duì)象,需要使用new的定義表達(dá)式顯式調(diào)用構(gòu)造函數(shù)進(jìn)行初始化。

下一節(jié)我們講模板初步,敬請(qǐng)期待