http://www.cnblogs.com/growup/archive/2011/06/27/2091101.htmlhtml
http://blog.csdn.net/passion_wu128/article/details/38966581web
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*指針。this
new delete在實現上其實調用了malloc,free函數編碼
6.new創建的對象你能夠把它當成一個普通的對象,用成員函數訪問,不要直接訪問它的地址空間;malloc分配的是一塊內存區域,就用指針訪問好了,並且還能夠在裏面移動指針.spa
7.new 創建的是一個對象;alloc分配的是一塊內存..net
***************************************scala
相同點:均可用於申請動態內存和釋放內存
不一樣點:
(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操做針對數據類型的處理,分爲兩種狀況:
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 bytes void *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也分爲兩種狀況:
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[]也分爲兩種狀況:
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[]也分爲兩種狀況:
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[]釋放。