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

C++ Placement New:在預先配置記憶體構造物件的技術與應用

     編輯:關於C++

應用場景

  • 自訂記憶體池/垃圾收集器:大塊預分配,物件在池內構造/銷毀,避免碎片與分配開銷
  • 即時系統:分配失敗風險不可接受,預留足夠緩衝
  • 物件重用:GUI 對話框、遊戲實體等頻繁建構/銷毀,固定緩衝區反覆使用

核心步驟

  1. 分配原始位元組緩衝:char* buf = new char[sizeof(Foo)];
  2. Placement new 構造:Foo* p = new (buf) Foo; (需 #include )
  3. 正常使用物件:p->method();
  4. 顯式呼叫解構函數:p->~Foo();
  5. 釋放緩衝:delete[] buf;

完整範例


#include 
#include 

class Foo {
    int id_;
public:
    Foo(int id = 0) : id_(id) { std::cout << "Foo(" << id_ << ") ctor\n"; }
    ~Foo() { std::cout << "Foo(" << id_ << ") dtor\n"; }
    void greet() { std::cout << "Hello from " << id_ << "\n"; }
};

void placement_demo() {
    // 1. 預分配緩衝 (足夠最大物件)
    char* buf = new char[sizeof(Foo)];

    // 2. 在緩衝構造物件
    Foo* p1 = new (buf) Foo(42);
    p1->greet();

    // 3. 顯式解構
    p1->~Foo();

    // 4. 同一緩衝構造不同型別 (假設 Bar 大小 <= Foo)
    // Bar* p2 = new (buf) Bar(...);
    // p2->~Bar();

    // 5. 釋放緩衝
    delete[] buf;
}

int main() {
    placement_demo();
    return 0;
}

輸出

Foo(42) ctor
Hello from 42
Foo(42) dtor

關鍵細節與陷阱

現代 C++ 封裝:記憶體池雛形


#include 
#include 

template 
class ObjectPool {
    std::vector> storage_;
    std::vector in_use_;
public:
    ObjectPool(size_t capacity) : storage_(capacity), in_use_(capacity, false) {}

    template 
    T* acquire(Args&&... args) {
        for (size_t i = 0; i < storage_.size(); ++i) {
            if (!in_use_[i]) {
                in_use_[i] = true;
                T* obj = new (&storage_[i]) T(std::forward(args)...);
                return obj;
            }
        }
        return nullptr; // 或擴容
    }

    void release(T* obj) {
        // 計算索引
        char* base = reinterpret_cast(storage_.data());
        char* ptr  = reinterpret_cast(obj);
        size_t idx = (ptr - base) / sizeof(storage_[0]);
        if (idx < in_use_.size() && in_use_[idx]) {
            obj->~T();
            in_use_[idx] = false;
        }
    }
};

標準庫支援

  • std::allocator_traits::construct/destroy 封裝 placement new / 解構呼叫
  • std::optional, std::variant 內部即使用 placement new 管理內建儲存
  • std::pmr::polymorphic_allocator (C++17) 整合記憶體資源與 placement new

總結

Placement new 將記憶體分配與物件構造分離,是高效能記憶體管理、物件池、即時系統的核心技術。關鍵紀律:**每個 placement new 必須配對一個顯式解構函數呼叫**,且記憶體釋放與物件解構完全分離。現代 C++ 建議封裝於 RAII 容器 (如上述 ObjectPool) 避免手動管理錯誤。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
議題說明
對齊需求緩衝位址必須滿足型別對齊。C++17 起可用 std::aligned_storage 或 alignas 保證
陣列 Placement Newnew (buf) Foo[N] 需手動逐個解構,極易出錯,建議避免
例外安全建構拋出異常時,緩衝未構造成功,無需解構;但若部分構造成功需手動回滾
解構順序與構造順序相反 (LIFO),手動管理時必須遵守
delete vs 解構函數delete p 會釋放記憶體,**不可用於 placement new 物件**;必須分離「解構」與「釋放記憶體」