new與malloc的幾點區別

new與malloc的區別


1. 申請的內存所在位置


new操作符從自由存儲區(free store)上爲對象動態分配內存空間,而malloc函數從堆上動態分配內存。自由存儲區是C++基於new操作符的一個抽象概念,凡是通過new操作符進行內存申請,該內存即爲自由存儲區。而堆是操作系統中的術語,是操作系統所維護的一塊特殊內存,用於程序的內存動態分配,C語言使用malloc從堆上分配內存,使用free釋放已分配的對應內存。


那麼自由存儲區是否能夠是堆(問題等價於new是否能在堆上動態分配內存),這取決於operator new 的實現細節。自由存儲區不僅可以是堆,還可以是靜態存儲區,這都看operator new在哪裏爲對象分配內存。


2.返回類型安全性


new操作符內存分配成功時,返回的是對象類型的指針,類型嚴格與對象匹配,無須進行類型轉換,故new是符合類型安全性的操作符。而malloc內存分配成功則是返回void * ,需要通過強制類型轉換將void*指針轉換成我們需要的類型。


類型安全很大程度上可以等價於內存安全,類型安全的代碼不會試圖方法自己沒被授權的內存區域。關於C++的類型安全性可說的又有很多了。


3.內存分配失敗時的返回值


new內存分配失敗時,會拋出bac_alloc異常,它不會返回NULL;malloc分配內存失敗時返回NULL。 在使用C語言時,我們習慣在malloc分配內存後判斷分配是否成功:


4.是否需要指定內存大小


使用new操作符申請內存分配時無須指定內存塊的大小,編譯器會根據類型信息自行計算,而malloc則需要顯式地指出所需內存的尺寸。


5.是否調用構造函數/析構函數


使用new操作符來分配對象內存時會經歷三個步驟:


第一步:調用operator new 函數(對於數組是operator new[])分配一塊足夠大的,原始的,未命名的內存空間以便存儲特定類型的對象。 

第二步:編譯器運行相應的構造函數以構造對象,併爲其傳入初值。 

第三部:對象構造完成後,返回一個指向該對象的指針。


使用delete操作符來釋放對象內存時會經歷兩個步驟:


第一步:調用對象的析構函數。 

第二步:編譯器調用operator delete(或operator delete[])函數釋放內存空間。


6.對數組的處理


C++提供了new[]與delete[]來專門處理數組類型:


A * ptr = new A[10];//分配10個A對象


使用new[]分配的內存必須使用delete[]進行釋放:


delete [] ptr;


new對數組的支持體現在它會分別調用構造函數函數初始化每一個數組元素,釋放對象時爲每個對象調用析構函數。注意delete[]要與new[]配套使用,不然會找出數組對象部分釋放的現象,造成內存泄漏。


至於malloc,它並知道你在這塊內存上要放的數組還是啥別的東西,反正它就給你一塊原始的內存,在給你個內存的地址就完事。所以如果要動態分配一個數組的內存,還需要我們手動自定數組的大小:


int * ptr = (int *) malloc( sizeof(int)* 10 );//分配一個10個int元素的數組


7.new與malloc是否可以相互調用


operator new /operator delete的實現可以基於malloc,而malloc的實現不可以去調用new。下面是編寫operator new /operator delete 的一種簡單方式,其他版本也與之類似:


8.是否可以被重載


opeartor new /operator delete可以被重載。標準庫是定義了operator new函數和operator delete函數的8個重載版本:


//這些版本可能拋出異常

void * operator new(size_t);

void * operator new[](size_t);

void * operator delete (void * )noexcept;

void * operator delete[](void *0noexcept;

//這些版本承諾不拋出異常

void * operator new(size_t ,nothrow_t&) noexcept;

void * operator new[](size_t, nothrow_t& );

void * operator delete (void *,nothrow_t& )noexcept;

void * operator delete[](void *0,nothrow_t& )noexcept;


我們可以自定義上面函數版本中的任意一個,前提是自定義版本必須位於全局作用域或者類作用域中。太細節的東西不在這裏講述,總之,我們知道我們有足夠的自由去重載operator new /operator delete ,以決定我們的new與delete如何爲對象分配內存,如何回收對象。


而malloc/free並不允許重載。


總結

特徵new/deletemalloc/free
分配內存的位置自由存儲區
內存分配成功的返回值完整類型指針void*
內存分配失敗的返回值默認拋出異常返回NULL
分配內存的大小由編譯器根據類型計算得出必須顯式指定字節數
處理數組有處理數組的new版本new[]需要用戶計算數組的大小後進行內存分配
已分配內存的擴充無法直觀地處理使用realloc簡單完成
是否相互調用可以,看具體的operator new/delete實現不可調用new
分配內存時內存不足客戶能夠指定處理函數或重新制定分配器無法通過用戶代碼進行處理
函數重載允許不允許
構造函數與析構函數調用不調用


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章