首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ new/delete 深度解析:operator new、placement new、數組分配、配對陷阱

     編輯:關於C++

new/delete 是關鍵字,不是函數

new 表達式完成兩件事:調用 operator new 分配原始內存,然後調用構造函數初始化對象。delete 反之:先調用析構函數,再調用 operator delete 釋放內存。

operator new / operator delete(標準庫函數)

void* operator new(std::size_t size);           // 單對象分配
void  operator delete(void* ptr) noexcept;      // 單對象釋放
void* operator new[](std::size_t size);         // 數組分配
void  operator delete[](void* ptr) noexcept;    // 數組釋放
  • 類似 malloc/free,但可重載、可拋異常(bad_alloc)。
  • 不進行對象構造/析構,僅管理原始內存。
  • 可直接調用:void* p = operator new(sizeof(Foo));。

new 表達式背後機制

Foo* p = new Foo(10);  // 單對象
// 等價於:
void* raw = operator new(sizeof(Foo));
Foo* p = new(raw) Foo(10);  // placement new 調用構造函數

delete 表達式背後機制

delete p;
// 等價於:
p->~Foo();                 // 顯式調用析構函數
operator delete(p);        // 釋放內存

數組 new[] / delete[] 的特殊處理

  • new Foo[3]:分配 3*sizeof(Foo) + 額外空間(通常 4/8 字節)存儲數組長度(cookie),調用 3 次構造函數,返回首元素地址(cookie 之後)。
  • delete[] p:讀取 cookie 獲取長度 N,逆序調用 N 次析構函數,釋放整個塊(含 cookie)。
  • 嚴禁混用:new[] 必須配 delete[],new 配 delete。混用導致析構次數錯誤、內存釋放地址錯誤、崩潰。

為什麼 new[] 配 delete 有時能跑通?

  • 內置類型(int、double)無析構函數,delete p 僅調用 operator delete(p)。若實現中 new[] 未存 cookie(某些編譯器對 POD 類型優化),則 p 指向塊首,delete 能正確釋放。但不可依賴,屬未定義行為。
  • 類類型有析構函數時,delete p 只會析構第 1 個對象,其餘洩漏;且釋放地址錯誤(未扣除 cookie),堆損壞必現。

Placement New(定位 new)

char buffer[sizeof(Foo)];
Foo* p = new(buffer) Foo(10);  // 在預備緩衝區構造對象
p->~Foo();  // 手動調用析構,不釋放 buffer 內存
  • 用於對象池、共享內存、嵌入式系統固定內存區。
  • 不分配內存,僅調用構造函數。

常見陷阱總結

代碼後果
new Foo[10]; delete p;僅析構 1 個,釋放地址偏移 → 崩潰/洩漏
new Foo; delete[] p;讀取不存在的 cookie → 未定義行為
忘記定義聲明的構造/析構鏈接錯誤(如 AAA a; 報錯,new AAA 不報直到 delete)
基類析構非 virtual刪除基類指針指向派生對象 → 派生析構未調用 → 資源洩漏

最佳實踐

  1. 現代 C++ 優先用智能指針(unique_ptr, shared_ptr)和容器,避免裸 new/delete。
  2. 必須手動管理時:嚴格配對,new/delete、new[]/delete[]。
  3. 類管理資源時遵循 Rule of Five。
  4. 基類析構 必須 virtual。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved