C++ new/delete、malloc/free
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
http://www.cnblogs.com/growup/archive/2011/06/27/2091101.html
http://blog.csdn.net/passion_wu128/article/details/38966581
new和delete最終調(diào)用malloc和free。
1.malloc與free是C++/C語言的標(biāo)準(zhǔn)庫函數(shù),new/delete是C++的運(yùn)算符。它們都可用于申請(qǐng)動(dòng)態(tài)內(nèi)存和釋放內(nèi)存
2.對(duì)于非內(nèi)部數(shù)據(jù)類型的對(duì)象而言,光用maloc/free無法滿足動(dòng)態(tài)對(duì)象的要求。對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)造函數(shù),對(duì)象在消亡之前要自動(dòng)執(zhí)行析構(gòu)函數(shù)。由malloc/free是庫函數(shù)而不是運(yùn)算符,不在編譯器控制權(quán)限之內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強(qiáng)加于malloc/free。
3.因此C++語言需要一個(gè)能完成動(dòng)態(tài)內(nèi)存分配和初始化工作的運(yùn)算符new,以一個(gè)能完成清理與釋放內(nèi)存工作的運(yùn)算符delete。注意new/delete不是庫函數(shù)。?
4.C++程序經(jīng)常要調(diào)用C函數(shù),而C程序只能用malloc/free管理動(dòng)態(tài)內(nèi)存。?
5.new可以認(rèn)為是malloc加構(gòu)造函數(shù)的執(zhí)行。new出來的指針是直接帶類型信息的。而malloc返回的都是void*指針。
new delete在實(shí)現(xiàn)上其實(shí)調(diào)用了malloc,free函數(shù)
6.new建立的對(duì)象你可以把它當(dāng)成一個(gè)普通的對(duì)象,用成員函數(shù)訪問,不要直接訪問它的地址空間;malloc分配的是一塊內(nèi)存區(qū)域,就用指針訪問好了,而且還可以在里面移動(dòng)指針.
7.new 建立的是一個(gè)對(duì)象;alloc分配的是一塊內(nèi)存.
***************************************
相同點(diǎn):都可用于申請(qǐng)動(dòng)態(tài)內(nèi)存和釋放內(nèi)存
不同點(diǎn):?
(1)操作對(duì)象有所不同。?
malloc與free是C++/C 語言的標(biāo)準(zhǔn)庫函數(shù),new/delete 是C++的運(yùn)算符。對(duì)于非內(nèi)部數(shù)據(jù)類的對(duì)象而言,光用maloc/free 無法滿足動(dòng)態(tài)對(duì)象的要求。對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)造函數(shù), 對(duì)象消亡之前要自動(dòng)執(zhí)行析構(gòu)函數(shù)。由于malloc/free 是庫函數(shù)而不是運(yùn)算符,不在編譯器控制權(quán)限之內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強(qiáng)加malloc/free。
(2)在用法上也有所不同。?
函數(shù)malloc 的原型如下:?
void * malloc(size_t size);?
用malloc 申請(qǐng)一塊長(zhǎng)度為length 的整數(shù)類型的內(nèi)存,程序如下:?
int *p = (int *) malloc(sizeof(int) * length);?
我們應(yīng)當(dāng)把注意力集中在兩個(gè)要素上:“類型轉(zhuǎn)換”和“sizeof”。?
malloc 返回值的類型是void *,所以在調(diào)用malloc 時(shí)要顯式地進(jìn)行類型轉(zhuǎn)換,將void * 轉(zhuǎn)換成所需要的指針類型。?
malloc 函數(shù)本身并不識(shí)別要申請(qǐng)的內(nèi)存是什么類型,它只關(guān)心內(nèi)存的總字節(jié)數(shù)。
函數(shù)free 的原型如下:?
void free( void * memblock );?
為什么free 函數(shù)不象malloc 函數(shù)那樣復(fù)雜呢?這是因?yàn)橹羔榩 的類型以及它所指的內(nèi)存的容量事先都是知道的,語句free(p)能正確地釋放內(nèi)存。如果p 是NULL 指針,那么free
對(duì)p 無論操作多少次都不會(huì)出問題。如果p 不是NULL 指針,那么free 對(duì)p連續(xù)操作兩次就會(huì)導(dǎo)致程序運(yùn)行錯(cuò)誤。
new/delete 的使用要點(diǎn)?
運(yùn)算符new 使用起來要比函數(shù)malloc 簡(jiǎn)單得多,例如:?
int *p1 = (int *)malloc(sizeof(int) * length);?
int *p2 = new int[length];?
這是因?yàn)閚ew 內(nèi)置了sizeof、類型轉(zhuǎn)換和類型安全檢查功能。對(duì)于非內(nèi)部數(shù)據(jù)類型的對(duì)象而言,new 在創(chuàng)建動(dòng)態(tài)對(duì)象的同時(shí)完成了初始化工作。如果對(duì)象有多個(gè)構(gòu)造函數(shù),那么new 的語句也可以有多種形式。
如果用new 創(chuàng)建對(duì)象數(shù)組,那么只能使用對(duì)象的無參數(shù)構(gòu)造函數(shù)。例如?
Obj *objects = new Obj[100]; // 創(chuàng)建100 個(gè)動(dòng)態(tài)對(duì)象?
不能寫成?
Obj *objects = new Obj[100](1);// 創(chuàng)建100 個(gè)動(dòng)態(tài)對(duì)象的同時(shí)賦初值1?
在用delete 釋放對(duì)象數(shù)組時(shí),留意不要丟了符號(hào)‘[]’。例如?
delete []objects; // 正確的用法?
delete objects; // 錯(cuò)誤的用法?
后者相當(dāng)于delete objects[0],漏掉了另外99 個(gè)對(duì)象。
***************************************
1? new自動(dòng)計(jì)算需要分配的空間,而malloc需要手工計(jì)算字節(jié)數(shù)?
2? new是類型安全的,而malloc不是,比如:?
int* p = new float[2]; // 編譯時(shí)指出錯(cuò)誤?
int* p = malloc(2*sizeof(float)); // 編譯時(shí)無法指出錯(cuò)誤?
new operator 由兩步構(gòu)成,分別是 operator new 和 construct?
3? operator new對(duì)應(yīng)于malloc,但operator new可以重載,可以自定義內(nèi)存分配策略,甚至不做內(nèi)存分配,甚至分配到非內(nèi)存設(shè)備上。而malloc無能為力?
4? new將調(diào)用constructor,而malloc不能;delete將調(diào)用destructor,而free不能。?
5? malloc/free要庫文件支持,new/delete則不要。
=============================================================
new
new操作針對(duì)數(shù)據(jù)類型的處理,分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要構(gòu)造函數(shù)的類型)
代碼實(shí)例:
int*?p?=?new?int;匯編碼如下:
int*?p?=?new?int; 00E54C44??push????????4?? 00E54C46??call????????operator?new?(0E51384h)?? 00E54C4B??add?????????esp,4分析:傳入4byte的參數(shù)后調(diào)用operator new。其源碼如下:
void?*__CRTDECL?operator?new(size_t?size)?_THROW1(_STD?bad_alloc){???????//?try?to?allocate?size?bytesvoid?*p;while?((p?=?malloc(size))?==?0)if?(_callnewh(size)?==?0){???????//?report?no?memory_THROW_NCEE(_XSTD?bad_alloc,?);}return?(p);}分析:調(diào)用malloc失敗后會(huì)調(diào)用_callnewh。如果_callnewh返回0則拋出bac_alloc異常,返回非零則繼續(xù)分配內(nèi)存。
這個(gè)_callnewh是什么呢?它是一個(gè)new handler,通俗來講就是new失敗的時(shí)候調(diào)用的回調(diào)函數(shù)。可以通過_set_new_handler來設(shè)置。下面舉個(gè)實(shí)例:
#include?<stdio.h> #include?<new.h> int?MyNewHandler(size_t?size) {printf("Allocation?failed.Try?again");return?1; //continue?to?allocate//return?0; //stop?allocating,throw?bad_alloc } void?main() {//?Set?the?failure?handler?for?new?to?be?MyNewHandler._set_new_handler(MyNewHandler);while?(1){int*?p?=?new?int[10000000];} }在new基本數(shù)據(jù)類型的時(shí)候還可以指定初始化值,比如:
int*?p?=?new?int(4);總結(jié):
簡(jiǎn)單類型直接調(diào)用operator new分配內(nèi)存;
可以通過new_handler來處理new失敗的情況;
new分配失敗的時(shí)候不像malloc那樣返回NULL,它直接拋出異常。要判斷是否分配成功應(yīng)該用異常捕獲的機(jī)制;
2,復(fù)雜數(shù)據(jù)類型(需要由構(gòu)造函數(shù)初始化對(duì)象)
代碼實(shí)例:
class?Object { public:Object(){_val?=?1;}~Object(){} private:int?_val; };void?main() {Object*?p?=?new?Object(); }匯編碼如下:
Object*?p?=?new?Object(); 00AD7EDD??push????????4?? 00AD7EDF??call????????operator?new?(0AD1384h)?? 00AD7EE4??add?????????esp,4?? 00AD7EE7??mov?????????dword?ptr?[ebp-0E0h],eax?? 00AD7EED??mov?????????dword?ptr?[ebp-4],0?? 00AD7EF4??cmp?????????dword?ptr?[ebp-0E0h],0?? 00AD7EFB??je??????????main+70h?(0AD7F10h)?? 00AD7EFD??mov?????????ecx,dword?ptr?[ebp-0E0h]?? 00AD7F03??call????????Object::Object?(0AD1433h)????????//在new的地址上調(diào)用構(gòu)造函數(shù) 00AD7F08??mov?????????dword?ptr?[ebp-0F4h],eax?? 00AD7F0E??jmp?????????main+7Ah?(0AD7F1Ah)?? 00AD7F10??mov?????????dword?ptr?[ebp-0F4h],0?? 00AD7F1A??mov?????????eax,dword?ptr?[ebp-0F4h]?? 00AD7F20??mov?????????dword?ptr?[ebp-0ECh],eax?? 00AD7F26??mov?????????dword?ptr?[ebp-4],0FFFFFFFFh?? 00AD7F2D??mov?????????ecx,dword?ptr?[ebp-0ECh]?? 00AD7F33??mov?????????dword?ptr?[p],ecx總結(jié):
new 復(fù)雜數(shù)據(jù)類型的時(shí)候先調(diào)用operator new,然后在分配的內(nèi)存上調(diào)用構(gòu)造函數(shù)。
delete
delete也分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)。
delete的匯編碼如下:
delete?p; 00275314??mov?????????eax,dword?ptr?[p]?? 00275317??mov?????????dword?ptr?[ebp-0D4h],eax?? 0027531D??mov?????????ecx,dword?ptr?[ebp-0D4h]?? 00275323??push????????ecx?? 00275324??call????????operator?delete?(0271127h)分析:傳入?yún)?shù)p之后調(diào)用operator delete,其源碼如下:
void?operator?delete(?void?*?p?) {RTCCALLBACK(_RTC_Free_hook,?(p,?0));free(?p?); }RTCCALLBACK默認(rèn)是空的宏定義,所以這個(gè)函數(shù)默認(rèn)情況下就是簡(jiǎn)單的調(diào)用free函數(shù)。
總結(jié):
delete簡(jiǎn)單數(shù)據(jù)類型默認(rèn)只是調(diào)用free函數(shù)。
2,復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)
代碼實(shí)例:
class?Object { public:Object(){_val?=?1;}~Object(){cout?<<?"destroy?object"?<<?endl;} private:int?_val; };void?main() {Object*?p?=?new?Object;delete?p; }部分匯編碼如下:
012241F0??mov?????????dword?ptr?[this],ecx?? 012241F3??mov?????????ecx,dword?ptr?[this]?? 012241F6??call????????Object::~Object?(0122111Dh)??????????????????????????//先調(diào)用析構(gòu)函數(shù) 012241FB??mov?????????eax,dword?ptr?[ebp+8]?? 012241FE??and?????????eax,1?? 01224201??je??????????Object::`scalar?deleting?destructor'+3Fh?(0122420Fh)?? 01224203??mov?????????eax,dword?ptr?[this]?? 01224206??push????????eax?? 01224207??call????????operator?delete?(01221145h)?? 0122420C??add?????????esp,4總結(jié):
delete復(fù)雜數(shù)據(jù)類型先調(diào)用析構(gòu)函數(shù)再調(diào)用operator delete。
new數(shù)組
new[]也分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)。
new[] 調(diào)用的是operator new[],計(jì)算出數(shù)組總大小之后調(diào)用operator new。
值得一提的是,可以通過()初始化數(shù)組為零值,實(shí)例:
char*?p?=?new?char[32]();等同于:
char?*p?=?new?char[32]; memset(p,?32,?0);總結(jié):
針對(duì)簡(jiǎn)單類型,new[]計(jì)算好大小后調(diào)用operator new。
2,復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)
實(shí)例:
class?Object { public:Object(){_val?=?1;}~Object(){cout?<<?"destroy?object"?<<?endl;} private:int?_val; };void?main() {Object*?p?=?new?Object[3]; }new[]先調(diào)用operator new[]分配內(nèi)存,然后在p的前四個(gè)字節(jié)寫入數(shù)組大小,最后調(diào)用三次構(gòu)造函數(shù)。
實(shí)際分配的內(nèi)存塊如下:
這里為什么要寫入數(shù)組大小呢?因?yàn)閷?duì)象析構(gòu)時(shí)不得不用這個(gè)值,舉個(gè)例子:
class?Object { public:Object(){_val?=?1;}virtual?~Object(){cout?<<?"destroy?Object"?<<?endl;} private:int?_val; };class?MyObject?:?public?Object { public:~MyObject(){cout?<<?"destroy?MyObject"?<<?endl;} private:int?_foo; };void?main() {Object*?p?=?new?MyObject[3];delete[]?p; }釋放內(nèi)存之前會(huì)調(diào)用每個(gè)對(duì)象的析構(gòu)函數(shù)。但是編譯器并不知道p實(shí)際所指對(duì)象的大小。如果沒有儲(chǔ)存數(shù)組大小,編譯器如何知道該把p所指的內(nèi)存分為幾次來調(diào)用析構(gòu)函數(shù)呢?
總結(jié):
針對(duì)復(fù)雜類型,new[]會(huì)額外存儲(chǔ)數(shù)組大小。
delete數(shù)組
delete[]也分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)。
delete和delete[]效果一樣
比如下面的代碼:
int*?pint?=?new?int[32]; delete?pint;char*?pch?=?new?char[32]; delete?pch;運(yùn)行后不會(huì)有什么問題,內(nèi)存也能完成的被釋放。看下匯編碼就知道operator delete[]就是簡(jiǎn)單的調(diào)用operator delete。
總結(jié):
針對(duì)簡(jiǎn)單類型,delete和delete[]等同。
2,復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)
釋放內(nèi)存之前會(huì)先調(diào)用每個(gè)對(duì)象的析構(gòu)函數(shù)。
new[]分配的內(nèi)存只能由delete[]釋放。如果由delete釋放會(huì)崩潰,為什么會(huì)崩潰呢?
假設(shè)指針p指向new[]分配的內(nèi)存。因?yàn)橐?字節(jié)存儲(chǔ)數(shù)組大小,實(shí)際分配的內(nèi)存地址為[p-4],系統(tǒng)記錄的也是這個(gè)地址。delete[]實(shí)際釋放的就是p-4指向的內(nèi)存。而delete會(huì)直接釋放p指向的內(nèi)存,這個(gè)內(nèi)存根本沒有被系統(tǒng)記錄,所以會(huì)崩潰。
總結(jié):
針對(duì)復(fù)雜類型,new[]出來的內(nèi)存只能由delete[]釋放。
轉(zhuǎn)載于:https://my.oschina.net/u/223340/blog/547018
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的C++ new/delete、malloc/free的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS 之 二维码生成与扫描(LBXSc
- 下一篇: c++多线程单例