堆是執行期動態分配的記憶體區域,大小不固定、生命週期由程式設計師手動控制。相對於棧(自動變數、函式呼叫幀),堆適合:
#include <cstdlib> // 或
int main() {
int n; cin >> n;
int* arr = static_cast<int*>(malloc(n * sizeof(int))); // 返回 void*,需強轉
if (!arr) { /* 處理分配失敗 */ }
for (int i = 0; i < n; ++i) arr[i] = i;
for (int i = 0; i < n; ++i) cout << arr[i] << ',';
cout << endl;
free(arr); // 必須配對釋放,否則洩漏
}
malloc 僅分配原始位元組,**不呼叫建構子**。free 僅釋放記憶體,**不呼叫解構子**。int main() {
int n; cin >> n;
int* arr = new int[n]; // 分配並預設初始化(int 不初始化)
// int* arr = new int[n](); // 值初始化為 0
for (int i = 0; i < n; ++i) arr[i] = i;
for (int i = 0; i < n; ++i) cout << arr[i] << ',';
cout << endl;
delete[] arr; // 陣列必須用 delete[],單一物件用 delete
}
new T[n]:分配記憶體 → 呼叫每個元素的**建構子**(依序)。delete[] ptr:呼叫每個元素的**解構子**(逆序) → 釋放記憶體。new T / delete ptr。std::bad_alloc(可用 new (std::nothrow) T 返回 nullptr)。| 特性 | malloc/free | new/delete |
|---|---|---|
| 建構子/解構子 | 不呼叫 | 自動呼叫 |
| 類型安全 | void* 需強轉 | 返回精確類型指標 |
| 失敗處理 | 返回 nullptr | 拋出 bad_alloc |
| 重載/自訂 | 不可 | 可重載 operator new/delete |
| 陣列處理 | 手動計算大小 | new T[n] / delete[] 自動管理 |
| 適用場景 | C 代碼、POD、與 C API 互操作 | C++ 類別物件、RAII、現代代碼 |
// 在預先分配的緩衝區上建構物件
char buffer[sizeof(MyClass)];
MyClass* obj = new (buffer) MyClass(args); // 不分配記憶體,只呼叫建構子
obj->~MyClass(); // 手動呼叫解構子,不釋放 buffer
用於高效能記憶體池、共享記憶體、嵌入式系統固定記憶體佈局。
std::unique_ptr<T[]>:獨佔陣列,自動 delete[]。std::shared_ptr<T>:共享擁有,控制區塊管理計數。std::vector<T>:動態陣列,自動擴容、縮減、記憶體管理。std::make_unique/make_shared:單一分配優化、異常安全。| 錯誤 | 後果 | 正確做法 |
|---|---|---|
delete arr; (陣列用 delete) | 未定義行為(通常只析構首元素,記憶體洩漏/崩潰) | delete[] arr; |
free(ptr) (new 分配) | 未定義行為 | 配對使用:new↔delete, malloc↔free |
| 重複釋放 | 堆損壞、崩潰 | 智慧指標、置 nullptr、RAII |
| 使用已釋放記憶體 | 未定義行為、安全漏洞 | 釋放後置 nullptr、作用域限制 |
| 類別物件用 malloc | 建構子未執行,成員未初始化 | 用 new 或 placement new |
堆記憶體管理是 C++ 核心技能。**現代 C++ 原則:盡量不直接呼叫 new/delete,改用標準容器與智慧指標**。必須手動管理時,嚴格遵循配對原則、區分陣列/單一物件、理解建構/解構語義,並建立 RAII 包裝器封裝裸指標。