C++ new/delete、malloc/free
2019獨角獸企業重金招聘Python工程師標準>>>
http://www.cnblogs.com/growup/archive/2011/06/27/2091101.html
http://blog.csdn.net/passion_wu128/article/details/38966581
new和delete最終調用malloc和free。
1.malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用于申請動態內存和釋放內存
2.對于非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加于malloc/free。
3.因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。?
4.C++程序經常要調用C函數,而C程序只能用malloc/free管理動態內存。?
5.new可以認為是malloc加構造函數的執行。new出來的指針是直接帶類型信息的。而malloc返回的都是void*指針。
new delete在實現上其實調用了malloc,free函數
6.new建立的對象你可以把它當成一個普通的對象,用成員函數訪問,不要直接訪問它的地址空間;malloc分配的是一塊內存區域,就用指針訪問好了,而且還可以在里面移動指針.
7.new 建立的是一個對象;alloc分配的是一塊內存.
***************************************
相同點:都可用于申請動態內存和釋放內存
不同點:?
(1)操作對象有所不同。?
malloc與free是C++/C 語言的標準庫函數,new/delete 是C++的運算符。對于非內部數據類的對象而言,光用maloc/free 無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數, 對象消亡之前要自動執行析構函數。由于malloc/free 是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加malloc/free。
(2)在用法上也有所不同。?
函數malloc 的原型如下:?
void * malloc(size_t size);?
用malloc 申請一塊長度為length 的整數類型的內存,程序如下:?
int *p = (int *) malloc(sizeof(int) * length);?
我們應當把注意力集中在兩個要素上:“類型轉換”和“sizeof”。?
malloc 返回值的類型是void *,所以在調用malloc 時要顯式地進行類型轉換,將void * 轉換成所需要的指針類型。?
malloc 函數本身并不識別要申請的內存是什么類型,它只關心內存的總字節數。
函數free 的原型如下:?
void free( void * memblock );?
為什么free 函數不象malloc 函數那樣復雜呢?這是因為指針p 的類型以及它所指的內存的容量事先都是知道的,語句free(p)能正確地釋放內存。如果p 是NULL 指針,那么free
對p 無論操作多少次都不會出問題。如果p 不是NULL 指針,那么free 對p連續操作兩次就會導致程序運行錯誤。
new/delete 的使用要點?
運算符new 使用起來要比函數malloc 簡單得多,例如:?
int *p1 = (int *)malloc(sizeof(int) * length);?
int *p2 = new int[length];?
這是因為new 內置了sizeof、類型轉換和類型安全檢查功能。對于非內部數據類型的對象而言,new 在創建動態對象的同時完成了初始化工作。如果對象有多個構造函數,那么new 的語句也可以有多種形式。
如果用new 創建對象數組,那么只能使用對象的無參數構造函數。例如?
Obj *objects = new Obj[100]; // 創建100 個動態對象?
不能寫成?
Obj *objects = new Obj[100](1);// 創建100 個動態對象的同時賦初值1?
在用delete 釋放對象數組時,留意不要丟了符號‘[]’。例如?
delete []objects; // 正確的用法?
delete objects; // 錯誤的用法?
后者相當于delete objects[0],漏掉了另外99 個對象。
***************************************
1? new自動計算需要分配的空間,而malloc需要手工計算字節數?
2? new是類型安全的,而malloc不是,比如:?
int* p = new float[2]; // 編譯時指出錯誤?
int* p = malloc(2*sizeof(float)); // 編譯時無法指出錯誤?
new operator 由兩步構成,分別是 operator new 和 construct?
3? operator new對應于malloc,但operator new可以重載,可以自定義內存分配策略,甚至不做內存分配,甚至分配到非內存設備上。而malloc無能為力?
4? new將調用constructor,而malloc不能;delete將調用destructor,而free不能。?
5? malloc/free要庫文件支持,new/delete則不要。
=============================================================
new
new操作針對數據類型的處理,分為兩種情況:
1,簡單數據類型(包括基本數據類型和不需要構造函數的類型)
代碼實例:
int*?p?=?new?int;匯編碼如下:
int*?p?=?new?int; 00E54C44??push????????4?? 00E54C46??call????????operator?new?(0E51384h)?? 00E54C4B??add?????????esp,4分析:傳入4byte的參數后調用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);}分析:調用malloc失敗后會調用_callnewh。如果_callnewh返回0則拋出bac_alloc異常,返回非零則繼續分配內存。
這個_callnewh是什么呢?它是一個new handler,通俗來講就是new失敗的時候調用的回調函數。可以通過_set_new_handler來設置。下面舉個實例:
#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基本數據類型的時候還可以指定初始化值,比如:
int*?p?=?new?int(4);總結:
簡單類型直接調用operator new分配內存;
可以通過new_handler來處理new失敗的情況;
new分配失敗的時候不像malloc那樣返回NULL,它直接拋出異常。要判斷是否分配成功應該用異常捕獲的機制;
2,復雜數據類型(需要由構造函數初始化對象)
代碼實例:
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的地址上調用構造函數 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總結:
new 復雜數據類型的時候先調用operator new,然后在分配的內存上調用構造函數。
delete
delete也分為兩種情況:
1,簡單數據類型(包括基本數據類型和不需要析構函數的類型)。
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)分析:傳入參數p之后調用operator delete,其源碼如下:
void?operator?delete(?void?*?p?) {RTCCALLBACK(_RTC_Free_hook,?(p,?0));free(?p?); }RTCCALLBACK默認是空的宏定義,所以這個函數默認情況下就是簡單的調用free函數。
總結:
delete簡單數據類型默認只是調用free函數。
2,復雜數據類型(需要由析構函數銷毀對象)
代碼實例:
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)??????????????????????????//先調用析構函數 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總結:
delete復雜數據類型先調用析構函數再調用operator delete。
new數組
new[]也分為兩種情況:
1,簡單數據類型(包括基本數據類型和不需要析構函數的類型)。
new[] 調用的是operator new[],計算出數組總大小之后調用operator new。
值得一提的是,可以通過()初始化數組為零值,實例:
char*?p?=?new?char[32]();等同于:
char?*p?=?new?char[32]; memset(p,?32,?0);總結:
針對簡單類型,new[]計算好大小后調用operator new。
2,復雜數據類型(需要由析構函數銷毀對象)
實例:
class?Object { public:Object(){_val?=?1;}~Object(){cout?<<?"destroy?object"?<<?endl;} private:int?_val; };void?main() {Object*?p?=?new?Object[3]; }new[]先調用operator new[]分配內存,然后在p的前四個字節寫入數組大小,最后調用三次構造函數。
實際分配的內存塊如下:
這里為什么要寫入數組大小呢?因為對象析構時不得不用這個值,舉個例子:
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; }釋放內存之前會調用每個對象的析構函數。但是編譯器并不知道p實際所指對象的大小。如果沒有儲存數組大小,編譯器如何知道該把p所指的內存分為幾次來調用析構函數呢?
總結:
針對復雜類型,new[]會額外存儲數組大小。
delete數組
delete[]也分為兩種情況:
1,簡單數據類型(包括基本數據類型和不需要析構函數的類型)。
delete和delete[]效果一樣
比如下面的代碼:
int*?pint?=?new?int[32]; delete?pint;char*?pch?=?new?char[32]; delete?pch;運行后不會有什么問題,內存也能完成的被釋放。看下匯編碼就知道operator delete[]就是簡單的調用operator delete。
總結:
針對簡單類型,delete和delete[]等同。
2,復雜數據類型(需要由析構函數銷毀對象)
釋放內存之前會先調用每個對象的析構函數。
new[]分配的內存只能由delete[]釋放。如果由delete釋放會崩潰,為什么會崩潰呢?
假設指針p指向new[]分配的內存。因為要4字節存儲數組大小,實際分配的內存地址為[p-4],系統記錄的也是這個地址。delete[]實際釋放的就是p-4指向的內存。而delete會直接釋放p指向的內存,這個內存根本沒有被系統記錄,所以會崩潰。
總結:
針對復雜類型,new[]出來的內存只能由delete[]釋放。
轉載于:https://my.oschina.net/u/223340/blog/547018
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的C++ new/delete、malloc/free的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS 之 二维码生成与扫描(LBXSc
- 下一篇: PostgreSQL · 特性介绍 ·