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

C++ 內存分配與對象構造分離:allocator 與 placement new 深度解析

     編輯:關於C++

為什麼要分離分配與構造?

標準 new 表達式會同時完成兩件事:

  1. 調用 operator new 分配原始內存
  2. 調用構造函數初始化對象

這在以下場景下效率低下:

  • 預分配大量內存池,按需構造對象(如 STL 容器擴容)
  • 對象構造成本高,且可能被立即覆蓋賦值
  • 需要精確控制對象生命週期(如內存池、對象池)

方案一:std::allocator 模板類

allocator<T> 提供類型感知的內存管理,核心接口:

模擬 vector::push_back 核心邏輯

template <class T>
class SimpleVector {
    static allocator<T> alloc;
    T* elements;      // 數組首地址
    T* first_free;    // 首個空閒位置
    T* end;           // 分配內存末尾

    void push_back(const T& val) {
        if (first_free == end) reallocate();  // 擴容
        alloc.construct(first_free, val);     // 原地構造
        ++first_free;
    }

    void reallocate() {
        size_t newCap = max(2 * (first_free - elements), size_t(1));
        T* newData = alloc.allocate(newCap);
        // 移動現有元素(C++11 移動語義)
        uninitialized_copy(make_move_iterator(elements),
                          make_move_iterator(first_free), newData);
        // 銷毀舊元素
        for (T* p = first_free; p != elements; ) alloc.destroy(--p);
        // 釋放舊內存
        if (elements) alloc.deallocate(elements, end - elements);
        // 更新指針
        elements = newData;
        first_free = elements + (first_free - elements);
        end = elements + newCap;
    }
};

方案二:operator new / delete + placement new

標準庫提供全局 operator new(size_t) 和 operator delete(void*) 分配/釋放原始字節內存。配合 placement new 實現原地構造:

// 分配原始內存(相當於 alloc.allocate)
T* raw = static_cast<T*>(operator new[](sizeof(T) * n));

// 在已分配內存上構造對象(相當於 alloc.construct)
new (raw + i) T(args);  // placement new 語法

// 顯式調用析構函數(相當於 alloc.destroy)
(raw + i)->~T();

// 釋放原始內存(相當於 alloc.deallocate)
operator delete[](raw);

placement new 關鍵優勢

  • 支持任意構造函數(allocator::construct 僅支持拷貝構造)
  • 避免臨時對象拷貝開銷(對於禁用拷貝的類型至關重要)
  • 無異常安全額外開銷

標準庫輔助算法

  • uninitialized_copy:拷貝構造到未初始化內存
  • uninitialized_fill:填充構造到未初始化內存
  • uninitialized_move:移動構造(C++17)

最佳實踐總結

  1. 優先使用 std::allocator:類型安全、異常安全、符合 STL 慣例
  2. 需要精細控制或特殊構造時使用 placement new
  3. 嚴格配對:allocate/construct 與 destroy/deallocate
  4. 內存池場景考慮對齊要求(alignas / std::aligned_storage)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
函數作用
allocate(n)分配 n 個 T 對象的未初始化內存
deallocate(p, n)釋放 p 指向的 n 個對象內存
construct(p, args)在 p 處構造 T 對象(調用構造函數)
destroy(p)調用 p 處對象的析構函數