首頁 > 軟體

一起來學習C++的動態記憶體管理

2022-03-30 13:01:18

1.new和delete

C語言記憶體管理方式在C++中可以繼續使用,但有些地方就無能為力而且使用起來比較麻煩,因此C++又提出了自己的記憶體管理方式:通過new和delete操作符進行動態記憶體管理

這裡在動態申請和釋放時一定要匹配使用

但是我們發現即使我們隨意使用程式也沒有崩潰,但是這些開闢的空間都是預設型別的

我們接下來試一下開闢自定義型別的空間程式是否會崩潰

我們執行程式,發現直接就崩潰了

那為什麼自定義的型別就不可以隨意使用釋放記憶體的函數呢?這就要探究malloc,free和new,delete的區別。我們先來看malloc和free

然後再看new和delete

2.new和delete在底層是怎麼實現的:

2.1new底層的實現: 我們先來new一個test型別的空間。

然後執行起來我們轉到反組合程式碼看看

總結new的實現就是呼叫operate new(size_t)函數,函數內部循壞呼叫malloc如果申請空間成功就返回,如果申請失敗就檢測是否有應對措施,如果提供就執行措施,再繼續malloc,如果未提供就丟擲異常。然後再呼叫建構函式將申請的記憶體初始化。

2.2delete底層的實現: 我們執行delete語句,轉到反組合來

進入不知名函數

那麼我們來看看operator delete(void *pt)函數是如何如何實現的

總結:delete 的實現就是先呼叫類中的解構函式,將物件中的資料清空,然後呼叫operator delete(void *pt)函數,將記憶體釋放掉。

2.3new []底層的實現:

執行完這一系列操作後就會呼叫n次建構函式,將物件構造成功總結:new []就是呼叫operate new[]函數,在operate new []中呼叫operate new函數執行剛剛的一系列操作,然後返回申請的記憶體。再呼叫n次建構函式將申請的記憶體初始化。

2.4delete []的實現:

總結:delete函數就是先呼叫n次解構函式將申請的記憶體空間中的資料清空,然後再呼叫operate delete()函數將記憶體釋放掉。

3.過載new和delete

既然有了new和delete這麼好的申請記憶體的方法,那我們為什麼還要重新實現new和delete呢?注意這裡的重新實現實現new和delete並不是重新實現new和delete的申請記憶體的方式,而是有時我們再debug版本下偵錯時需要一些列印輸出一些資訊,這裡我們需要再用new申請記憶體的時候要實現輸出一些資訊。比如說列印檔名,呼叫函數,呼叫行數等等。我們重新實現new將我們的檔案資訊,呼叫函數,呼叫行數都列印出來

可以看到雖然將函數都列印出來了但是傳參的時候需要傳許多引數,所以我們可以用宏替換的方式來解決

但是我們需要這些資訊都是在偵錯的時候才需要,所以我們可以條件編譯一下只在debug版本底下執行

我們將delete實現過載,

注意這裡如果我們將delete自己實現過載之後再呼叫delete過載函數是不會呼叫類中的解構函式的,如果我們的物件中涉及了資源的申請那麼就不會釋放。

4.定位new:

使用場景:在有些場景下我們可能會申請一塊記憶體空間,但是這塊記憶體空間並沒有初始化,當我們想要使用這塊記憶體空間時,想給他初始化,對於類型別的物件我們想要給他初始化時,只能呼叫建構函式初始化,但是建構函式只能在建立時由編譯器自動呼叫(就像人不可以選擇自己的出生時間),那我們這時就要使用定位new來給已經申請號的記憶體中建立一個物件。

定位new的幾種使用方式:

釋放空間時

定位new的原理:

5.記憶體檢測函數:_CrtDumpMemoryLeaks();

_CrtDumpMemoryLeaks();函數是window作業系統提供的一個api(應用程式介面)函數,當程式中有記憶體漏失時就會在底行輸出記憶體漏失資訊。

我們將申請的空間正確釋放,可以看到沒有任何的提示。

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!


IT145.com E-mail:sddin#qq.com