日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ new/delete、malloc/free

發布時間:2025/3/19 c/c++ 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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,簡單數據類型(包括基本數據類型和不需要析構函數的類型)。

int?*p?=?new?int(1); delete?p;

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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。