【C++】C++ new和malloc到底哪裡不一樣
作者:李春港
出處://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++異常捕捉和處理的文章了解://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完成 |
分配記憶體時記憶體不足 | 可以指定處理函數或重新制定分配器 | 無法通過用戶程式碼進行處理 |
是否可以重載 | 可以 | 不可以 |
構造函數與析構函數 | 調用 | 不調用 |