C++ 無自動垃圾回收,手動 new/delete 易導致內存洩露、重複釋放、異常安全問題。智能指針通過 RAII(資源獲取即初始化) 機制,在棧對象析構時自動釋放堆內存。本文系統講解 7 種智能指針的特性、適用場景與避坑指南。
operator*、operator-> 模擬裸指針行為get() 獲取裸指針;reset() 釋放當前/接管新對象if (ptr.get()) 而非 if (ptr)(後者永真)特點:獨占所有權,複製/賦值會轉移所有權(源指針置空)。
std::auto_ptr<int> p1(new int(10)); std::auto_ptr<int> p2 = p1; // p1 變空,p2 接管 // p1 現在是空指針!使用會崩潰
致命缺陷:
release() 僅釋放所有權不釋放內存,易洩露delete 而非 delete[])結論:嚴禁在新代碼中使用,改用 unique_ptr。
特點:獨占所有權,禁止複製/賦值(編譯期報錯),無轉移所有權機制。
boost::scoped_ptr<int> p1(new int(10)); // boost::scoped_ptr<int> p2 = p1; // 編譯錯誤! // p1.reset(); // 手動釋放 // 無 release(),析構自動 delete
適用場景:函數局部資源管理、類成員唯一擁有、無需共享/轉移所有權的簡單場景。scoped_array 管理動態數組。
特點:內部維護引用計數,支持複製、賦值、容器存儲、參數傳遞。計數歸零時自動 delete。
boost::shared_ptr<int> p1(new int(10)); boost::shared_ptr<int> p2 = p1; // 計數 = 2 cout << p1.use_count(); // 2 p1.reset(); // 計數 = 1,內存未釋放 p2.reset(); // 計數 = 0,自動 delete
weak_ptr,使用時 lock() 轉為 shared_ptrstd::shared_ptr 計數操作原子化,線程安全| 方式 | 計數變化 | 適用場景 |
|---|---|---|
傳值 func(shared_ptr<T> p) | +1/-1 | 被調用方需共享所有權、延長生命週期 |
傳常量引用 func(const shared_ptr<T>& p) | 不變 | 被調用方僅觀察/短期使用,調用方保證生命週期 |
傳裸指針/引用 func(T* p) | 不變 | 不共享所有權,僅在調用方生命週期內訪問 |
特點:不增加引用計數,僅觀察 shared_ptr 管理的對象。對象銷毀後自動失效(expired() 返回 true)。
boost::shared_ptr<int> sp(new int(10));
boost::weak_ptr<int> wp = sp; // 計數仍為 1
cout << wp.use_count(); // 1
if (auto locked = wp.lock()) { // 安全獲取 shared_ptr
cout << *locked;
}
sp.reset(); // 對象銷毀
cout << wp.expired(); // true
shared_ptr,B 持有 A 的 weak_ptrweak_ptr,不阻礙對象釋放weak_ptr,用時 lock()特點:不自帶引用計數,要求被管理對象自行實現 intrusive_ptr_add_ref、intrusive_ptr_release。適用於已有引用計數機制的框架(如 COM、某些 GUI 庫)。
class MyObject {
int ref_ = 0;
friend void intrusive_ptr_add_ref(MyObject* p) { ++p->ref_; }
friend void intrusive_ptr_release(MyObject* p) { if (--p->ref_ == 0) delete p; }
};
boost::intrusive_ptr<MyObject> p(new MyObject()); // 調用 add_ref
一般應用層極少直接使用,了解即可。
// 簡易引用計數表
class HeapTable {
struct Node { void* addr; int count; Node* next; };
Node* head;
// ... 增/減/查引用計數 ...
};
template<typename T>
class CSmartPtr {
T* ptr;
static HeapTable table;
public:
CSmartPtr(T* p = nullptr) : ptr(p) { if (ptr) table.AddRef(ptr); }
CSmartPtr(const CSmartPtr& other) : ptr(other.ptr) { if (ptr) table.AddRef(ptr); }
CSmartPtr& operator=(const CSmartPtr& other) {
if (this == &other) return *this;
release();
ptr = other.ptr;
if (ptr) table.AddRef(ptr);
return *this;
}
~CSmartPtr() { release(); }
void release() { if (ptr && table.DelRef(ptr) == 0) delete ptr; }
T& operator*() { return *ptr; }
T* operator->() { return ptr; }
};
std::unique_ptr / std::shared_ptr / std::weak_ptrscoped_ptr/scoped_arrayshared_ptr/shared_arrayweak_ptrintrusive_ptrauto_ptr代碼中不應出現裸
delete/free。所有堆資源由智能指針(或 RAII 容器)管理,構造時綁定,析構時自動釋放,實現異常安全、無洩露的資源管理。





