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

深入理解 C++ 中的 new 與 delete:操作符、函數與 placement new

     編輯:關於C++

前言:術語的陷阱

C++ 的術語有時令人困惑,例如 new operator(new 操作符)與 operator new 的區別。兩者僅一字之差,卻代表完全不同的機制。搞混它們可能導致記憶體管理錯誤。本文將釐清這些概念,並探討 placement new 以及陣列 new/delete 的細節。

new 操作符:語言內建、行為固定

當你撰寫 string *ps = new string("Memory Management"); 時,使用的是 new 操作符。它如同 sizeof 一樣是語言內建關鍵字,無法改變其行為。它的工作固定包含兩步:

  1. 呼叫 operator new 配置足夠的原始記憶體。
  2. 在該記憶體上呼叫建構函式初始化物件。

編譯器產生的代碼大致相當於:

void *memory = operator new(sizeof(string)); // 1. 配置原始記憶體
new (memory) string("Memory Management");    // 2. 呼叫建構函式 (placement new 語法)
string *ps = static_cast<string*>(memory);   // 3. 指標指向新物件

注意:程式設計師不能直接呼叫建構函式來初始化堆上物件,這是編譯器的專屬權利。

operator new:可自訂的記憶體配置函數

operator new 是一個可被重載的函數,負責「僅配置記憶體」,不負責建構。標準宣告如下:

void* operator new(std::size_t size) noexcept(false);
  • 回傳 void* 指向未初始化的原始記憶體。
  • 第一個參數必須是 size_t,可增加額外參數形成重載(如 placement new)。
  • 類似 malloc,它不知建構函式為何物。

你通常不直接呼叫它,但若直接呼叫:void* raw = operator new(sizeof(string)); 只會給你一塊夠大的記憶體,裡面沒有 string 物件。

Placement New:在指定記憶體上建構物件

有時我們已擁有一塊記憶體(如共享記憶體、memory-mapped I/O、預先配置的緩衝區),想在上面建構物件。這時使用 placement new:

Widget* constructWidgetInBuffer(void* buffer, int widgetSize) {
    return new (buffer) Widget(widgetSize); // 傳遞額外參數 buffer
}

對應的 operator new 簽名為:

void* operator new(std::size_t, void* location) noexcept {
    return location; // 直接回傳呼叫者提供的位址
}

需包含 <new> 標頭。Placement new 不配置記憶體,只負責在既有記憶體上呼叫建構函式。

陣列 new / delete:operator new[] 與 operator delete[]

配置陣列時:string* ps = new string[10];

  • 仍使用 new operator,但配置記憶體改呼叫 operator new[](array new)。
  • 會對每個元素呼叫預設建構函式。
  • 刪除時 delete[] ps; 會對每個元素呼叫解構函式,再呼叫 operator delete[] 釋放記憶體。

operator new[] 和 operator delete[] 同樣可重載,允許自訂陣列記憶體管理。早期編譯器若不支援,會退回使用全域 operator new,導致自訂困難。

總結:核心區別一覽

名稱性質可否改變行為主要職責
new operator語言關鍵字否配置記憶體 + 呼叫建構函式
operator new可重載函數是僅配置原始記憶體
placement new特定重載形式是 (標準庫提供)在指定位址建構物件
operator new[]可重載函數是配置陣列原始記憶體
delete operator語言關鍵字否呼叫解構函式 + 釋放記憶體
operator delete可重載函數是僅釋放原始記憶體

核心原則:你無法改變 new/delete 操作符「做什麼」(配置+建構/解構+釋放),但可透過重載 operator new/delete 改變它們「怎麼做」(記憶體配置/釋放策略)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved