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

C++ new 運算子、operator new 與 Placement New 三重奏完整指南

     編輯:關於C語言

三種 new 的身分證

類別語法本質可否重載自動建構
new 運算子new T(args)語言關鍵字否是
operator newoperator new(sz)函式(可重載)是否
Placement newnew (ptr) T(args)operator new 重載形式是(標準庫提供)是

new 運算子執行流程

string* ps = new string("hello");
// 編譯器展開為:
void* raw = operator new(sizeof(string));  // 1. 配置原始記憶體
string* ps = static_cast<string*>(raw);   // 2. 型別轉換
ps->string::string("hello");               // 3. 呼叫建構函式(編譯器內部語法)

operator new 重載指南

全域重載

void* operator new(size_t sz) {
    if (void* p = malloc(sz)) return p;
    throw std::bad_alloc();
}
void* operator new[](size_t sz) { return operator new(sz); }

類別專屬重載

class Widget {
public:
    void* operator new(size_t sz) { return pool_.alloc(sz); }
    void operator delete(void* p) noexcept { pool_.free(p); }
    // 陣列版
    void* operator new[](size_t sz) { return pool_.alloc(sz); }
    void operator delete[](void* p) noexcept { pool_.free(p); }
};

對齊需求(C++17)

void* operator new(size_t sz, std::align_val_t al) {
    void* p = std::aligned_alloc(static_cast<size_t>(al), sz);
    if (!p) throw std::bad_alloc();
    return p;
}

Placement New 深度解析

標準形式

#include <new>  // 必須包含

// 形式 1:指定位址
char buf[sizeof(Widget)];
Widget* pw = new (buf) Widget();           // 在 buf 建構

// 形式 2:帶初始化引數
int val = 42;
int* pi = new (&val) int(99);             // 覆寫 val 為 99

// 形式 3:陣列 placement new(C++20)
alignas(Widget) char buf[N * sizeof(Widget)];
Widget* arr = new (buf) Widget[N];         // 建構陣列

對應的 operator new 簽名

void* operator new(size_t, void* ptr) noexcept { return ptr; }
void* operator new[](size_t, void* ptr) noexcept { return ptr; }

不配置記憶體,直接回傳指定位址;建構失敗(拋出例外)時不會呼叫對應 operator delete,必須手動解構。

實際應用場景

  • STL 容器節點配置:std::allocator::construct() 內部使用 placement new
  • 記憶體池/物件池:預先配置大塊記憶體,placement new 逐個建構
  • 共享記憶體/記憶體映射檔:在固定位址建構資料結構
  • 自訂對齊:new (std::align_val_t(64)) Widget(C++17)

new 失敗處理機制

模式行為適用場景
擲出例外(預設)throw std::bad_alloc一般應用
nothrownew (std::nothrow) T 失敗回傳 nullptr無例外環境、嵌入式
自訂 new_handlerstd::set_new_handler() 設定回呼嘗試釋放記憶體記憶體緊張時自救

五大核心法則

  1. 運算子 new 不可重載,僅能重載 operator new 函式
  2. operator new 不呼叫建構函式,僅回傳原始記憶體
  3. Placement new 不配置記憶體,釋放時只能顯式呼叫解構函式
  4. 重載 operator new 必須配對重載 operator delete
  5. 陣列 new[] 需配對 delete[],中間插入建構/解構循環

現代 C++ 建議

  • 應用層代碼 極少直接呼叫 new/delete
  • 使用 std::make_unique、std::make_shared、std::vector、std::string
  • 自訂配置器透過 std::allocator 或 std::pmr::polymorphic_allocator 注入容器
  • Placement new 僅用於底層庫實作(配置器、容器、序列化框架)

掌握 new 的三重身分與生命週期,才能在需要極致效能、特殊記憶體模型時,正確駕馭 C++ 底層機制。

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