c new delete 常踩的坑

2021-08-03 12:59:43 字數 2359 閱讀 2657

c++ 是公司開發最常用的語言之一, 那new和delete 這兩個函式是所有開發者即愛又恨的函式。由new 和delete引發的bug , coredump , 讓多少程式設計師加了多少班。

c++ 中,你也許經常使用 new 和 delete 來動態申請和

● 釋放記憶體,但你可曾想過以下問題呢?

● new 和 delete 是函式嗎?

● new 和 delete 又是什麼?什麼時候用它們?

● 你知道 operator new 和 operator delete 嗎?

為什麼 new 出來的陣列有時可以用 delete 釋放有時又不行?

有時看到**是這麼寫的:

這樣有問題嗎 ? 在伺服器上長期執行,會引起記憶體洩漏嗎?

寫了個測試程式, 看看這些都是神馬。

程式執行結果:

注意這裡多出來的 4位元組

這個問題直接導致我們需要在 new 乙個物件陣列時,需要儲存陣列的維度,c++ 的做法是在分配陣列空間時多分配了 4 個位元組的大小,專門儲存陣列的大小,

在 delete 時就可以取出這個儲存的數,就知道了需要呼叫析構函式多少次了。

有人提出兩個問題:

1、那個4位元組在 delete  , 是怎麼跳過的。

2、free 是怎麼知道自己的長度。

以下寫幾個栗子 看一下:

delete 物件 :

部分彙編碼如下:

delete複雜資料型別先呼叫析構函式再呼叫operator delete。

c++的記憶體分配

看一下 m$ 編譯器是如何構造和釋放記憶體的

記憶體分配一般有兩種方式:

1 非入侵式,記憶體分配器自行先申請記憶體(和棧配合使用),用作記錄使用者層的申請記錄(位址,大小)。 使用者釋放空間時會查詢該錶,除了知道釋放空間大小外還能判斷該指標是合法。

2 入侵式,例如使用者要申請1byte的記憶體,而記憶體分配器會分配5byte的空間(32位),前面4byte用於申請的大小。釋放記憶體時會先向前偏移4個byte找到申請大小,再進行釋放。

兩種方法各有優缺點,第一種安全,但慢。第二種快但對程式設計師的指標控制能力要求更高,稍有不慎越界了會對空間資訊做成破壞。

絕大多數的分配器會採用第一種方式實現,而作業系統級的分配器採用了虛擬等方式,可能要記錄更多資訊。

那麼陣列的分配和釋放是 怎麼自動的 增加 4 位元組 和 減 4位元組的呢?

實在不想看了 ,貼一點 關鍵的吧 , new 物件的部分彙編

上面的彙編碼流程大致是:

1、呼叫operator new分配堆空間

2、呼叫構造**函式構造堆物件,在呼叫構造**函式時,通過壓棧,像其傳遞了5個引數,分別是 a)第乙個堆物件首位址 b)堆物件大小c)堆物件個數 d)建構函式位址 e)析構函式位址

3、傳回第乙個堆物件首位址,而不是申請到的堆空間首位址

析構的部分**

看看析構函式是如何自動偏移4位元組的。

以上的彙編似乎沒有涉及 4位元組的偏移 , 那看看 vector deleting destructor 這個函式幹了啥

看到 operator delete (0341244h) 這個函式了 , 前面將 物件首位址 -4 ,然後釋放記憶體, 現在知道為啥 析構偏移4位元組了吧

c new delete 常踩的坑

c 是公司開發最常用的語言之一,那new和delete 這兩個函式是所有開發者即愛又恨的函式。由new 和delete引發的bug coredump 讓多少程式設計師加了多少班。一 遇到的問題 c 中,你也許經常使用 new 和 delete 來動態申請和 釋放記憶體,但你可曾想過以下問題呢?new...

軟體測試員常踩的7個坑,不想再入坑者必看

1.自以為了解業務邏輯,實際浮於表面 這是個深坑,產品迭代跟的久了,功能上閉著眼睛都能說清楚就自以為很了解,實際上連該功能使用的協議,呼叫的介面都不知道,所以看到問題都是表面的問題。你只看到了兩個操作的入口不一樣,提示資訊不一樣,你就以為是兩個問題,而這兩個問題都是調同乙個介面引起的,但你分析不出來...

systemtap embedded C 踩坑筆記

官方文件 systemtap的embedded c中,不能 include 也不能用printf和print。那怎麼列印呢?用stap printf。用法與printf一樣。還可以訪問cript中的全域性變數。官方文件中的示例 global var global var2 100 function ...