1. 屬性
new/delete是C++關(guān)鍵字,需要編譯器支持惩琉。malloc/free是庫(kù)函數(shù)豆励,需要頭文件支持。
2. 參數(shù)
使用new操作符申請(qǐng)內(nèi)存分配時(shí)無(wú)須指定內(nèi)存塊的大小琳水,編譯器會(huì)根據(jù)類(lèi)型信息自行計(jì)算肆糕。而malloc則需要顯式地指出所需內(nèi)存的尺寸。
3. 返回類(lèi)型
new操作符內(nèi)存分配成功時(shí)在孝,返回的是對(duì)象類(lèi)型的指針诚啃,類(lèi)型嚴(yán)格與對(duì)象匹配,無(wú)須進(jìn)行類(lèi)型轉(zhuǎn)換私沮,故new是符合類(lèi)型安全性的操作符始赎。而malloc內(nèi)存分配成功則是返回void * ,需要通過(guò)強(qiáng)制類(lèi)型轉(zhuǎn)換將void*指針轉(zhuǎn)換成我們需要的類(lèi)型。
4. 調(diào)用構(gòu)造函數(shù)/析構(gòu)函數(shù)
使用new操作符來(lái)分配對(duì)象內(nèi)存時(shí)會(huì)經(jīng)歷三個(gè)步驟:
- 調(diào)用operator new 函數(shù)(對(duì)于數(shù)組是operator new[])分配一塊足夠大的造垛,原始的魔招,未命名的內(nèi)存空間以便存儲(chǔ)特定類(lèi)型的對(duì)象。
- 編譯器運(yùn)行相應(yīng)的構(gòu)造函數(shù)以構(gòu)造對(duì)象五辽,并為其傳入初值办斑。
- 對(duì)象構(gòu)造完成后,返回一個(gè)指向該對(duì)象的指針杆逗。
使用delete操作符來(lái)釋放對(duì)象內(nèi)存時(shí)會(huì)經(jīng)歷兩個(gè)步驟:
- 調(diào)用對(duì)象的析構(gòu)函數(shù)乡翅。
- 編譯器調(diào)用operator delete(或operator delete[])函數(shù)釋放內(nèi)存空間。
5. 對(duì)數(shù)組的處理
C++提供了new[]與delete[]來(lái)專(zhuān)門(mén)處理數(shù)組類(lèi)型:
A * ptr = new A[10]; //分配10個(gè)A對(duì)象
使用new[]分配的內(nèi)存必須使用delete[]進(jìn)行釋放:
delete [] ptr;
new對(duì)數(shù)組的支持體現(xiàn)在它會(huì)分別調(diào)用構(gòu)造函數(shù)函數(shù)初始化每一個(gè)數(shù)組元素罪郊,釋放對(duì)象時(shí)為每個(gè)對(duì)象調(diào)用析構(gòu)函數(shù)蠕蚜。注意delete[]要與new[]配套使用,不然會(huì)找出數(shù)組對(duì)象部分釋放的現(xiàn)象悔橄,造成內(nèi)存泄漏靶累。
使用malloc分配一個(gè)數(shù)組的內(nèi)存,需要指定數(shù)組的大醒⑴薄:
int * ptr = (int *) malloc( sizeof(int)* 10 ); //分配一個(gè)10個(gè)int元素的數(shù)組
6. 重載
C++允許重載new/delete操作符opeartor new /operator delete函數(shù)挣柬;malloc/free不允許重載。
7. 內(nèi)存區(qū)域
new操作符從自由存儲(chǔ)區(qū)(free store)上為對(duì)象動(dòng)態(tài)分配內(nèi)存空間争舞,而malloc函數(shù)從堆上動(dòng)態(tài)分配內(nèi)存凛忿。自由存儲(chǔ)區(qū)是C++基于new操作符的一個(gè)抽象概念澈灼,凡是通過(guò)new操作符進(jìn)行內(nèi)存申請(qǐng)竞川,該內(nèi)存即為自由存儲(chǔ)區(qū)。而堆是操作系統(tǒng)中的術(shù)語(yǔ)叁熔,是操作系統(tǒng)所維護(hù)的一塊特殊內(nèi)存委乌,用于程序的內(nèi)存動(dòng)態(tài)分配遭贸,C語(yǔ)言使用malloc從堆上分配內(nèi)存心软,使用free釋放已分配的對(duì)應(yīng)內(nèi)存删铃。自由存儲(chǔ)區(qū)不等于堆,如上所述咒劲,布局new就可以不位于堆中。(TODO:自由存儲(chǔ)區(qū)與堆的區(qū)別帐偎?)
8. 內(nèi)存分配失敗
new內(nèi)存分配失敗時(shí)削樊,會(huì)拋出bac_alloc異常兔毒。malloc分配內(nèi)存失敗時(shí)返回NULL。
在operator new拋出異常以反映一個(gè)未獲得滿(mǎn)足的需求之前绕辖,它會(huì)先調(diào)用一個(gè)用戶(hù)指定的錯(cuò)誤處理函數(shù)仪际,這就是new_handler昵骤。new_handler是一個(gè)指針類(lèi)型:
namespace std
{
typedef void (*new_handler)();
}
指向了一個(gè)沒(méi)有參數(shù)沒(méi)有返回值的函數(shù),即為錯(cuò)誤處理函數(shù)成榜。為了指定錯(cuò)誤處理函數(shù)赎婚,用戶(hù)需要調(diào)用set_new_handler樱溉,這是一個(gè)聲明于標(biāo)準(zhǔn)庫(kù)的函數(shù):
namespace std
{
new_handler set_new_handler(new_handler p ) throw();
}
set_new_handler的參數(shù)為new_handler指針,指向了operator new 無(wú)法分配足夠內(nèi)存時(shí)該調(diào)用的函數(shù)撩嚼。其返回值也是個(gè)指針完丽,指向set_new_handler被調(diào)用前正在執(zhí)行(但馬上就要發(fā)生替換)的那個(gè)new_handler函數(shù)拇舀。
當(dāng)new_handler執(zhí)行并返回之后,之前失敗的內(nèi)存分配操作會(huì)重新進(jìn)行瓷耙,如果仍然分配失敗朱躺,分配函數(shù)(operator new, operator new[])會(huì)繼續(xù)調(diào)用new_handler长搀,周而復(fù)始源请,直到new_handler==nullptr彻况,分配函數(shù)會(huì)拋出std::bad_alloc異常。
9. 直觀(guān)地重新分配內(nèi)存
使用malloc分配的內(nèi)存后良蛮,如果在使用過(guò)程中發(fā)現(xiàn)內(nèi)存不足悍赢,可以使用realloc函數(shù)進(jìn)行內(nèi)存重新分配實(shí)現(xiàn)內(nèi)存的擴(kuò)充。realloc先判斷當(dāng)前的指針?biāo)竷?nèi)存是否有足夠的連續(xù)空間左权,如果有赏迟,原地?cái)U(kuò)大可分配的內(nèi)存地址,并且返回原來(lái)的地址指針甩栈;如果空間不夠谤职,先按照新指定的大小分配空間,將原有數(shù)據(jù)從頭到尾拷貝到新分配的內(nèi)存區(qū)域,而后釋放原來(lái)的內(nèi)存區(qū)域冤吨。
new沒(méi)有這樣直觀(guān)的配套設(shè)施來(lái)擴(kuò)充內(nèi)存漩蟆。(實(shí)際使用中,可能只有想對(duì)數(shù)組擴(kuò)容時(shí)圾叼,才會(huì)遇到這種情況)
參考資料:
[1] 經(jīng)典面試題之new和malloc的區(qū)別
[2] 細(xì)說(shuō)new與malloc的10點(diǎn)區(qū)別
[3] cppreference: set_new_handler