智能指針是現代 C++ 資源管理核心。本文聚焦實踐中易忽視的細節:動態數組支持、刪除器類型擦除、Lambda 捕獲陷阱、第三方庫內存托管模式。
unique_ptr<T[]> p(new T[n]),析構自動 delete[]。shared_ptr<T[]>(C++17 前)。需自定義刪除器:// 正確寫法
shared_ptr p(new int[10], [](int* ptr){ delete[] ptr; });
// 或使用 default_delete
shared_ptr p(new int[10], default_delete());
// 封裝工廠函數
template
shared_ptr make_shared_array(size_t n) {
return shared_ptr(new T[n], default_delete());
}
| shared_ptr | unique_ptr | |
|---|---|---|
| 語法 | 構造函數第 2 參數 | 模板第 2 參數(類型) |
| Lambda 無捕獲 | 自動推導 | 可轉函數指針 void(*)(T*) |
| Lambda 有捕獲 | 自動推導 | 不可轉函數指針,需用 function<void(T*)> |
// unique_ptr 指定帶捕獲 Lambda 的刪除器
unique_ptr> p(new int(1), [&](int* ptr){ delete ptr; log(); });
// 自定義刪除器結構體
struct MyDeleter { void operator()(int* p) { cout<<"del"; delete p; } };
unique_ptr p(new int(1));
場景:第三方庫提供 Create()/Release(),必須配對調用,否則洩漏。智能指針通過自定義刪除器完美解決:
void* handle = Lib::Create();
// 危險:手動管理
// Lib::Release(handle);
// 安全:shared_ptr 托管
shared_ptr guard(handle, [](void* p){ Lib::Release(p); });
// 甚至封裝宏避免忘記賦值
#define GUARD(ptr) shared_ptr ptr##_guard(ptr, [](void* p){ Lib::Release(p); })
// 使用
void* p = Lib::Create();
GUARD(p); // 編譯期強制綁定變量名,防止臨時對象提前釋放
#define GUARD(ptr) unique_ptr ptr##_guard(ptr, [](void* p){ Lib::Release(p); })
注意:Lambda 無捕獲才能轉函數指針;有捕獲需用 function 但 unique_ptr 模板參數需完整類型,較繁瑣。
make_unique(單對象),數組版 make_unique<T[]>(n)。shared_ptr 支持數組 shared_ptr<T[]>,自動 delete[]。std::atomic<shared_ptr> 原子操作。善用智能指針能消滅 90% 內存洩漏。關鍵在於:理解所有權語義、正確指定刪除器、封裝第三方資源為 RAII 類型。