C++ 故意不內建統一垃圾回收(GC),但透過 RAII(資源獲取即初始化)、智慧指標、標準容器 等機制,已能在不犧牲效能、不破壞底層控制力的前提下,解決 99% 的記憶體管理問題。本文從語言哲學切入,逐步建構適用於不同場景的「按需 GC」方案。
Bjarne Stroustrup 在《The Design and Evolution of C++》中指出:
「我有意設計 C++ 不依賴自動 GC。基於經驗,我懼怕其嚴重的時空開銷、實現與移植複雜度,以及 GC 會讓 C++ 不適合底層系統程式設計——這正是其設計目標之一。但我喜歡 GC 的思想,它能簡化設計、消除大量錯誤根源。」
核心哲學:「不為不使用的功能付費」。統一 GC 強迫所有程式承擔開銷,違背 C++ 精神。
資源(記憶體、鎖、檔案控制代碼)在建構時獲取,解構時自動釋放:
class String {
char* data_;
public:
String(const char* s) { data_ = new char[strlen(s)+1]; strcpy(data_, s); }
~String() { delete[] data_; }
const char* c_str() const { return data_; }
};
void foo() {
String s("hello"); // 區域物件,離開作用域自動釋放
std::cout << s.c_str();
} // 此處自動呼叫 ~String(),零洩漏
甚至發生例外時,C++ 保證堆疊展開會正確呼叫解構子——這就是異常安全的基石。
獨佔所有權,移動語義轉移擁有權,零額外開銷:
#include <memory>
void bar() {
std::unique_ptr<String> p(new String("hello")); // C++11
// std::auto_ptr<String> p(new String("hello")); // C++98 僅供參考
std::cout << p->c_str();
} // 自動 delete
auto_ptr 的複製語義是所有權轉移(來源變空),易誤用;unique_ptr 禁止複製,只能 std::move,編譯期強制安全。
引用計數機制,最後一個 shared_ptr 銷毀時自動釋放資源:
template <typename T>
class shared_ptr {
struct ControlBlock { T* ptr; size_t refs; /* weak count */ };
ControlBlock* ctrl_;
// ... 建構、複製、移動、解構、operator*, operator->
void dec() { if (--ctrl_->refs == 0) { delete ctrl_->ptr; delete ctrl_; } }
};
用法:
void foo1(std::shared_ptr<int>& p) {
std::shared_ptr<int> tmp(p); // 計數 +1
*tmp = 300; // 修改共享物件
} // tmp 解構,計數 -1,物件存活
void foo2(std::shared_ptr<int>& p) {
p = std::make_shared<int>(200); // 重新指派,舊物件計數 -1
}
int main() {
auto p = std::make_shared<int>(100);
foo1(p); // 共享修改
foo2(p); // 替換為新物件
// 離開 main 時自動釋放,全程無 delete
}
注意:循環參考需配合 std::weak_ptr 打斷;多執行緒下控制區塊的引用計數為原子操作,有微小開銷。
std::vector、std::list、std::map 等容器內部以 RAII 管理元素生命週期:
避免 在容器中存放原始指標(std::vector<T*>),否則容器銷毀不會釋放物件,極易洩漏。
若標準智慧指標無法滿足(如效能極致、特定所有權語義),可自行實作:
new/delete。gc.h 等可選整合,但需評估移植性與效能影響。| 場景 | 推薦方案 | 關鍵點 |
|---|---|---|
| 區域物件、單一擁有者 | 值型別 / unique_ptr | 零開銷、移動語義、編譯期禁止複製 |
| 多擁有者、共享生命週期 | shared_ptr + weak_ptr | 引用計數、打斷循環參考、執行緒安全控制區塊 |
| 容器管理多態物件 | vector<unique_ptr<Base>> / vector<shared_ptr<Base>> | 避免物件切割、自動釋放、異質集合 |
| 高效能、大量短命物件 | Object Pool / Arena Allocator | 減少系統呼叫、提升快取局部性 |
| C API 互操作 | unique_ptr 自訂 Deleter / shared_ptr 自訂 Deleter | 封裝 malloc/free、CloseHandle 等 |
C++ 沒有「垃圾回收器」,但擁有更強大的「資源管理框架」:
掌握這套體系,你就擁有了比 GC 更精確、更高效、更適合系統級開發的記憶體管理能力。