| 特性 | new / delete | malloc / free |
|---|---|---|
| 屬性 | C++ 運算子 | C 標準庫函數 |
| 建構/解構 | 自動呼叫建構函數/解構函數 | 僅配置/釋放原始記憶體 |
| 型別安全 | 回傳具型別指標 | 回傳 void*,需強制轉型 |
| 大小指定 | 由編譯器依型別自動計算 | 需手動指定位元組數 |
| 失敗處理 | 拋出 std::bad_alloc 例外 | 回傳 NULL |
| 可重載性 | 可全域/類別內重載 | 不可重載 |
| 陣列支援 | new[] / delete[] 專用語法 | 手動計算總大小 |
| 底層實作 | 通常呼叫 malloc/free | 作業系統記憶體配置器 |
// 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. 釋放原始記憶體
類別專屬記憶體管理:
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 容器使用 Allocator 抽象記憶體配置:
// 自定義配置器範例 templatestruct 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; // 使用記憶體池
unique_ptr, shared_ptr) 避免手動管理