C 詳談malloc和new的區別

2021-10-11 03:05:15 字數 3978 閱讀 5348

3.new運算子

4.delete運算子

5.定位new表示式

6.總結

函式原型

void

* malloc (size_t size)

;

函式解釋:向系統申請size個位元組的空間,返回值為void*型別。在堆上申請空間,使用者使用時,可對這段空間進行強轉成任意型別指標。

實際上申請的空間數會大於size個位元組,另一部分空間記錄了此次申請記憶體的大小及起始位置等資訊。

函式原型

void free (

void

* ptr)

;

函式解釋:對malloc申請的記憶體進行釋放,無返回值。

注意:釋放記憶體,不是將該塊空間給刪了,而是將該指標指向的這塊空間歸還給系統,該指標不能再訪問該空間(為野指標了),所以一般情況下,釋放空間之後,並將該指標置為null,避免出現野指標。

malloc在開闢空間的時候,會額外開闢空間,該空間就記錄了開闢記憶體的大小,和起始位置,對其釋放就可以了。

會造成記憶體洩漏。

造成記憶體洩漏的幾個情況:

開闢了空間,忘記釋放

更改了返回指標的起始位置,這樣的情況更可怕,我們無法對該記憶體進行操作,其它程式也無法訪問該記憶體。

若在長期執行的程式中,記憶體洩漏是很嚴重的問題。程式在結束執行後,會自動將這些記憶體歸還給系統。

注意:malloc申請的記憶體,要檢查是否申請成功;malloc申請的記憶體要記得釋放,否則就會造成記憶體洩漏;不要對已經釋放的記憶體進行釋放,即double free,會造成錯誤,abort;free(null)指標不會報錯,但沒有意義。

c++中,引入了new和delete運算子實現對記憶體的動態管理。

int

*arr =

newint

;int

*brr =

newint[4

];

不需要指定具體的位元組數,即可申請空間。

堆是os所維護的一塊特殊記憶體,它提供了動態分配的空間,通過malloc申請、free釋放。而c++中new申請的記憶體區域可被稱為自由儲存區。對於大部分c++編譯器預設使用堆來實現自由儲存,即預設的全域性運算子new和delete也許會按照malloc和free的方式來被實現,這是new出來的記憶體,可以說在堆上,也可以說在自由儲存區上。但也可以過載new運算子,改用其它記憶體來實現自有儲存。

結論:

自由儲存是c++中通過new與delete動態分配和釋放物件的抽象概念,而堆(heap)是c語言和作業系統的術語,是作業系統維護的一塊動態分配記憶體。

new所申請的記憶體區域在c++中稱為自由儲存區。藉由堆實現的自由儲存,可以說new所申請的記憶體區域在堆上。

堆與自由儲存區還是有區別的,它們並非等價。

malloc對於申請內建型別的物件來說,是完全沒有問題的,但如果我們申請的是class物件呢,malloc就無法滿足要求了,這時就有了new運算子。

new在建立類物件時,都做了什麼事情?

呼叫乙個operator new()(或者operator new)的標準庫函式。該函式分配一塊足夠大的、原始的、未命名的記憶體空間以便儲存特定類的物件(或物件陣列)。

編譯器執行相應的建構函式以構造這些物件,並未其傳入初始值。

物件被分配了空間並構造完成,返回乙個指向該物件的指標。

如果使用malloc開闢,只是申請了一塊和類物件大小相同的空間,而不是乙個類物件。

對new申請的物件進行銷毀,銷毀記憶體型別的物件時,和free相同。

free在銷毀類物件時,都做了什麼事情?

先呼叫該物件的析構函式

編譯器呼叫名為operator delete(或operator delete),釋放記憶體空間 如:

string *s =

newstring

("i am you");

delete s;

反彙編一步一步追蹤下去:

注意:new和delete,new和delete,要搭配使用,否則就會出錯。

標準庫定義了operator new函式和operator delete函式的8個過載版本。其中前四個版本可能會丟擲bad_alloc異常,後四個版本不會丟擲異常:

會拋異常

void

*operator

new(size_ t)

//分配乙個物件

void

*operator

new[

](size_ t)

//分配乙個陣列

void

*operator

delete

(void*)

noexcept

//釋放乙個物件

void

*operator

delete

(void*)

noexcept

//釋放乙個陣列

不會拋異常

void

*operator

new(size_t,nothrow_t &

)noexcept

void

*operator

new[

](size_t,nothrow_t &

)noexcept

void

*operator

delete

(size_t,nothrow_t &

)noexcept

void

*operator

delete

(size_t,nothrow_t &

)noexcept

定位new表示式是在已分配的原始記憶體空間中條用建構函式初始化乙個物件。

new

(place_address) type

new(place_address) type (initializers)

// initializers為初始化內容

new(place_address) type [size]

new(place_address) type [size]

// initializer list初始化列表

引數

說明place_address

必須為乙個指標

initializers

初始化內容

type

物件名size

多少個注意:當只傳入乙個指標型別的實參時,定位new表示式只構造物件但是不分配記憶體。

物件呼叫析構函式可以清除給定的物件,但是不會釋放該物件所在的空間。如果需要的話,還可以重新使用該空間。

呼叫析構函式會銷毀物件,但不會釋放記憶體。

new/delete

malloc/free

本質運算子

庫函式記憶體位置

自由儲存區

堆申請成功返回值型別

和申請指標的型別相同

void*,使用時需要強轉

申請失敗返回值

拋異常,bad_alloc

null

初始化可以初始化

不會初始化

申請自定義型別物件

會呼叫建構函式和析構函式

只會開闢該空間的大小

函式過載

支援operator new / new/delete/delete 過載

不支援分配記憶體大小

跟上記憶體型別即可

需要手動計算空間大小

釋放方式

new,delete / new ,delete搭配使用

free釋放

部分參考:

malloc函式 new和malloc的區別

1 申請的記憶體所在位置 new操作符從自由儲存區上為物件動態分配記憶體空間,而malloc函式從堆上動態分配記憶體。自由儲存區是c 基於new操作符的乙個抽象概念,凡是通過new操作符進行記憶體申請,該記憶體即為自由儲存區。而堆是作業系統中的術語,是作業系統所維護的一塊特殊記憶體,用於程式的記憶體...

C 中new和malloc記憶體區問題

參考如下 這裡有解釋 基本上來說,很多編譯器都是預設new是呼叫malloc來開闢記憶體的,那麼都是呼叫malloc來開闢乙個記憶體區的那麼問題來了。這個時候到底是自由記憶體區還是堆記憶體?自由記憶體區在c中是沒有的,在c 中才被提及的乙個抽象概念。那麼在一般情況下不過載修改開闢方式或者說開闢記憶體...

堆區和棧區,malloc和new的區別

1.堆區和棧區的區別 1.1 申請方式 堆區變數是由程式設計師自己申請並指明大小 棧區變數是由作業系統負責分配 1.2 生命週期 堆區變數程式設計師自己釋放,或者等待程式結束系統自動 記憶體洩漏 棧區變數是當申請棧區變數的大括號結束後系統自動 1.3 申請後系統的響應 棧 只要棧的剩餘空間大於所申請...