目錄
- 1.malloc函式
- 2.free函式
- 2.1 free是如何做到釋放具體空間的大小的?
- 2.2 不對malloc開辟的空間進行free會怎么樣?
- 3.new運算子
- 3.1new申請的空間是在堆上嘛?
- 3.2有了malloc為什么還需要new?
- 4.delete運算子
- 4.1operator new介面和operator delete介面
- 5.定位new運算式
- 5.1顯式呼叫解構式
- 6.總結
1.malloc函式
函式原型
void* malloc (size_t size);
函式解釋:向系統申請size個位元組的空間,回傳值為void*型別,在堆上申請空間,用戶使用時,可對這段空間進行強轉成任意型別指標,
實際上申請的空間數會大于size個位元組,另一部分空間記錄了此次申請記憶體的大小及起始位置等資訊,
2.free函式
函式原型
void free (void* ptr);
函式解釋:對malloc申請的記憶體進行釋放,無回傳值,
注意:釋放記憶體,不是將該塊空間給刪了,而是將該指標指向的這塊空間歸還給系統,該指標不能再訪問該空間(為野指標了),所以一般情況下,釋放空間之后,并將該指標置為NULL,避免出現野指標,
2.1 free是如何做到釋放具體空間的大小的?
malloc在開辟空間的時候,會額外開辟空間,該空間就記錄了開辟記憶體的大小,和起始位置,對其釋放就可以了,
2.2 不對malloc開辟的空間進行free會怎么樣?
會造成記憶體泄漏,
造成記憶體泄漏的幾個情況:
- 開辟了空間,忘記釋放
- 更改了回傳指標的起始位置,這樣的情況更可怕,我們無法對該記憶體進行操作,其它程式也無法訪問該記憶體,
若在長期運行的程式中,記憶體泄漏是很嚴重的問題,程式在結束運行后,會自動將這些記憶體歸還給系統,
注意:malloc申請的記憶體,要檢查是否申請成功;malloc申請的記憶體要記得釋放,否則就會造成記憶體泄漏;不要對已經釋放的記憶體進行釋放,即double free,會造成錯誤,abort;free(NULL)指標不會報錯,但沒有意義,
3.new運算子
C++中,引入了new和delete運算子實作對記憶體的動態管理,
int *arr = new int;
int *brr = new int[4];
不需要指定具體的位元組數,即可申請空間,
3.1new申請的空間是在堆上嘛?
堆是OS所維護的一塊特殊記憶體,它提供了動態分配的空間,通過malloc申請、free釋放,而C++中new申請的記憶體區域可被稱為自由存盤區,對于大部分C++編譯器默認使用堆來實作自由存盤,即預設的全域運算子new和delete也許會按照malloc和free的方式來被實作,這是new出來的記憶體,可以說在堆上,也可以說在自由存盤區上,但也可以多載new運算子,改用其它記憶體來實作自有存盤,
結論:
- 自由存盤是C++中通過new與delete動態分配和釋放物件的抽象概念,而堆(heap)是C語言和作業系統的術語,是作業系統維護的一塊動態分配記憶體,
- new所申請的記憶體區域在C++中稱為自由存盤區,藉由堆實作的自由存盤,可以說new所申請的記憶體區域在堆上,
- 堆與自由存盤區還是有區別的,它們并非等價,
3.2有了malloc為什么還需要new?
malloc對于申請內置型別的物件來說,是完全沒有問題的,但如果我們申請的是class物件呢,malloc就無法滿足要求了,這時就有了new運算子,
new在創建類物件時,都做了什么事情?
- 呼叫一個
operator new()(或者operator new[])的標準庫函式,該函式分配一塊足夠大的、原始的、未命名的記憶體空間以便存盤特定類的物件(或物件陣列), - 編譯器運行相應的建構式以構造這些物件,并未其傳入初始值,
- 物件被分配了空間并構造完成,回傳一個指向該物件的指標,
如果使用malloc開辟,只是申請了一塊和類物件大小相同的空間,而不是一個類物件,
4.delete運算子
對new申請的物件進行銷毀,銷毀記憶體型別的物件時,和free相同,
free在銷毀類物件時,都做了什么事情?
- 先呼叫該物件的解構式
- 編譯器呼叫名為
operator delete(或operator delete[]),釋放記憶體空間
如:
string *s = new string("i am you");
delete s;
反匯編一步一步追蹤下去:

注意:new和delete,new[]和delete[],要搭配使用,否則就會出錯,
4.1operator new介面和operator 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
5.定位new運算式
定位new運算式是在已分配的原始記憶體空間中條用建構式初始化一個物件,
new (place_address) type
new (place_address) type (initializers) // initializers為初始化內容
new (place_address) type [size]
new (place_address) type [size] {braced initializer list} // initializer list初始化串列
| 引數 | 說明 |
|---|---|
| place_address | 必須為一個指標 |
| initializers | 初始化內容 |
| type | 物件名 |
| size | 多少個 |
注意:當只傳入一個指標型別的實參時,定位new運算式只構造物件但是不分配記憶體,
5.1顯式呼叫解構式
物件呼叫解構式可以清除給定的物件,但是不會釋放該物件所在的空間,如果需要的話,還可以重新使用該空間,
呼叫解構式會銷毀物件,但不會釋放記憶體,
6.總結
| new/delete | malloc/free | |
|---|---|---|
| 本質 | 運算子 | 庫函式 |
| 記憶體位置 | 自由存盤區 | 堆 |
| 申請成功回傳值型別 | 和申請指標的型別相同 | void*,使用時需要強轉 |
| 申請失敗回傳值 | 拋例外,bad_alloc | NULL |
| 初始化 | 可以初始化 | 不會初始化 |
| 申請自定義型別物件 | 會呼叫建構式和解構式 | 只會開辟該空間的大小 |
| 函式多載 | 支持operator new / new[]/delete/delete []多載 | 不支持 |
| 分配記憶體大小 | 跟上記憶體型別即可 | 需要手動計算空間大小 |
| 釋放方式 | new,delete / new [],delete[]搭配使用 | free釋放 |
部分參考:
- https://blog.csdn.net/linux_ever/article/details/50533149
- https://www.cnblogs.com/QG-whz/p/5060894.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/229481.html
標籤:其他
