作者:李春港
出處:https://www.cnblogs.com/lcgbk/p/14118782.html
一、前言
new和malloc的知識點,作為一個C++工程師是必須要了解清楚的,在面試中該知識點也是經常會被詢問到的。所以在此文章,總結下new和malloc的區別到底在哪裡。
二、new和malloc兩者的區別
2.1 屬性的區別
- new/delete:這兩個是C++中的關鍵字,若要使用,需要編譯器支援;
- malloc/free:這兩個是庫函式,若要使用則需要引入相應的標頭檔案才可以正常使用。
2.2 使用上的區別
- malloc:申請空間需要顯式填入申請記憶體的大小;
- new:無需顯式填入申請的記憶體大小,new會根據new的型別分配記憶體。
例項:
/** malloc/free用例 **/
int *ma = (int*) malloc(4);
free(ma);
/** new/delete用例 **/
int *ne = new int(0);
2.3 記憶體位置的區別
- new:此操作符分配的記憶體空間是在自由儲存區;
- malloc:申請的記憶體是在堆空間。
C/C++的記憶體通常分為:堆、棧、自由儲存區、全域性/靜態儲存區、常量儲存區。可能除了自由儲存區,其他的記憶體分佈大家應該都比較熟悉。
堆 是C語言和作業系統的術語,堆是作業系統所維護的一塊特殊記憶體,它提供了動態分配的功能,當執行程式呼叫malloc()時就會從中分配,呼叫free()歸還記憶體。那什麼是自由儲存區呢?
自由儲存區 是C++中動態分配和釋放物件的一個概念,通過new分配的記憶體區域可以稱為自由儲存區,通過delete釋放歸還記憶體。自由儲存區可以是堆、全域性/靜態儲存區等,具體是在哪個區,主要還是要看new的實現以及C++編譯器預設new申請的記憶體是在哪裡。但是基本上,很多C++編譯器預設使用堆來實現自由儲存,運算子new和delete內部預設是使用malloc和free的方式來被實現,說它在堆上也對,說它在自由儲存區上也正確。因為在C++中new和delete符號是可以過載的,我們可以重新實現new的實現程式碼,可以讓其分配的記憶體位置在靜態儲存區等。而malloc和free是C裡的庫函式,無法對其進行過載。
2.4 返回型別的區別
new操作符記憶體分配成功時,返回的是物件型別的指標,型別嚴格與物件匹配,無須進行型別轉換,故new是符合型別安全性的操作符。而malloc記憶體分配成功則是返回void * ,需要通過強制型別轉換將void*指標轉換成我們需要的型別。所以在C++程式中使用new會比malloc安全可靠。
2.5 分配失敗情況的區別
malloc分配記憶體失敗時返回NULL,我們可以通過判斷返回值可以得知是否分配成功;
new記憶體分配失敗時,會丟擲bac_alloc異常,它不會返回NULL,分配失敗時如果不捕捉異常,那麼程式就會異常退出,我們可以通過異常捕捉的方式獲取該異常,具體C++異常捕捉和處理的使用可以通過我往期【C++】 C++異常捕捉和處理的文章瞭解:https://www.cnblogs.com/lcgbk/p/13858425.html。
2.6 定義物件系統排程過程的區別
使用new操作符來分配物件記憶體時會經歷三個步驟:
- 呼叫operator new 函式(對於陣列是operator new[])分配一塊足夠的記憶體空間(通常底層預設使用malloc實現,除非程式設計師過載new符號)以便儲存特定型別的物件;
- 編譯器執行相應的建構函式以構造物件,併為其傳入初值。
- 物件構造完成後,返回一個指向該物件的指標。
使用delete操作符來釋放物件記憶體時會經歷兩個步驟:
- 呼叫物件的解構函式。
- 編譯器呼叫operator delete(或operator delete[])函式釋放記憶體空間(通常底層預設使用free實現,除非程式設計師過載delete符號)。
自己可以通過例項去驗證下,此處就不展開例程了。
2.7 擴張記憶體大小的區別
- malloc:使用malloc分配記憶體後,發現記憶體不夠用,那我們可以通過realloc函式來擴張記憶體大小,realloc會先判斷當前申請的記憶體後面是否還有足夠的記憶體空間進行擴張,如果有足夠的空間,那麼就會往後面繼續申請空間,並返回原來的地址指標;否則realloc會在另外有足夠大小的記憶體申請一塊空間,並將當前記憶體空間裡的內容拷貝到新的記憶體空間裡,最後返回新的地址指標。
- new:new沒有擴張記憶體的機制。
三、總結
特徵 | new/delete | malloc/free |
---|---|---|
分配記憶體的位置 | 自由儲存區 | 堆 |
記憶體分配失敗 | 丟擲異常 | 返回NULL |
分配記憶體的大小 | 編譯器根據型別計算得出 | 顯式指定位元組數 |
處理陣列 | 有處理陣列的new版本new[] | 需要使用者計算陣列的大小後進行記憶體分配 |
已分配記憶體的擴張 | 不支援 | 使用realloc完成 |
分配記憶體時記憶體不足 | 可以指定處理函式或重新制定分配器 | 無法通過使用者程式碼進行處理 |
是否可以過載 | 可以 | 不可以 |
建構函式與解構函式 | 呼叫 | 不呼叫 |