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

C++ 記憶體管理核心:new/delete 與 malloc/free 深度對比與實務指南

     編輯:C++ 入門

核心差異速查表

特性new / deletemalloc / free
屬性C++ 運算子C 標準庫函數
建構/解構自動呼叫建構函數/解構函數僅配置/釋放原始記憶體
型別安全回傳具型別指標回傳 void*,需強制轉型
大小指定由編譯器依型別自動計算需手動指定位元組數
失敗處理拋出 std::bad_alloc 例外回傳 NULL
可重載性可全域/類別內重載不可重載
陣列支援new[] / delete[] 專用語法手動計算總大小
底層實作通常呼叫 malloc/free作業系統記憶體配置器

關鍵機制深度解析

new/delete 兩階段操作

// new T 實際執行:
void* raw = operator new(sizeof(T));  // 1. 配置原始記憶體
T* obj = new(raw) T();                // 2. 定位 new 呼叫建構函數

// delete ptr 實際執行:
ptr->~T();                             // 1. 呼叫解構函數
operator delete(ptr);                  // 2. 釋放原始記憶體

重載 new/delete 的威力

類別專屬記憶體管理:

class TrackedObject {
    static size_t totalAllocated;
    static std::set livePointers;
public:
    void* operator new(size_t size) {
        void* p = malloc(size);
        totalAllocated += size;
        livePointers.insert(p);
        return p;
    }
    void operator delete(void* p) noexcept {
        livePointers.erase(p);
        free(p);
    }
    // 陣列版本
    void* operator new[](size_t size) { return operator new(size); }
    void operator delete[](void* p) noexcept { operator delete(p); }
};

應用場景:記憶體洩漏追蹤、自定義記憶體池、效能分析、記憶體對齊控制。

經典錯誤與最佳實務

❌ 絕對禁止:混用配對

int* p = new int;
free(p);           // 錯誤!未呼叫解構函數 (對 int 影響小,但對類別致命)

int* q = (int*)malloc(sizeof(int));
delete q;          // 錯誤!free 可能用不同堆疊/配置器

原因:重載 operator new 可能使用完全不同的配置策略 (記憶體池、共享記憶體、對齊配置),free 無法正確釋放。

✅ 正確用法範例

class Buffer {
    int* data;
public:
    Buffer() : data(new int[1024]) {}           // 陣列 new[]
    ~Buffer() { delete[] data; data = nullptr; } // 陣列 delete[]
    
    // 規則五:拷貝/移動語意
    Buffer(const Buffer&) = delete;
    Buffer& operator=(const Buffer&) = delete;
    Buffer(Buffer&& other) noexcept : data(other.data) { other.data = nullptr; }
    Buffer& operator=(Buffer&& other) noexcept {
        if (this != &other) { delete[] data; data = other.data; other.data = nullptr; }
        return *this;
    }
};

int main() {
    // 單一物件
    int* p = new int(42);
    delete p; p = nullptr;
    delete p; // 安全:delete nullptr 無操作
    
    // 陣列
    double* arr = new double[100];
    delete[] arr; // 必須用 delete[]
    
    // 物件
    Buffer buf; // RAII 自動管理
    
    // C 風格 (需搭配 C API 時)
    int* c_style = (int*)malloc(sizeof(int));
    *c_style = 100;
    free(c_style); c_style = nullptr;
    free(c_style); // 安全:free(nullptr) 無操作
}

進階主題:配置器與 STL 容器

STL 容器使用 Allocator 抽象記憶體配置:

// 自定義配置器範例
template
struct PoolAllocator {
    using value_type = T;
    T* allocate(size_t n) { return static_cast(pool.alloc(n * sizeof(T))); }
    void deallocate(T* p, size_t n) { pool.free(p, n * sizeof(T)); }
};

std::vector> vec; // 使用記憶體池

工具建議

  • BoundsChecker / Valgrind:記憶體洩漏/越界檢測
  • AddressSanitizer (ASan):編譯器內建,效能影響小
  • Visual Studio 診斷工具:整合式記憶體分析

總結

  1. C++ 程式優先使用 new/delete,保證建構/解構語意
  2. 嚴禁混用,除非極特殊情況且完全理解底層實作
  3. 善用 RAII 與智慧指標 (unique_ptr, shared_ptr) 避免手動管理
  4. 需要自定義記憶體策略時重載 operator new/delete
  5. 配配器模式讓 STL 容器支援自定義記憶體管理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved