shared_ptr 採引用計數管理物件生命週期。當兩個物件互相持有對方的 shared_ptr 時,計數永不歸零,導致記憶體洩漏。
struct Node {
int data;
shared_ptr<Node> next;
shared_ptr<Node> prev; // 雙向連結
};
void testCycle() {
auto n1 = make_shared<Node>();
auto n2 = make_shared<Node>();
cout << n1.use_count() << ' ' << n2.use_count() << endl; // 1 1
n1->next = n2;
n2->prev = n1;
cout << n1.use_count() << ' ' << n2.use_count() << endl; // 2 2
} // 離開作用域,n1/n2 計數 2→1,物件未釋放!

weak_ptr 不增加引用計數,專為打破循環設計。需配合 shared_ptr 使用,無法單獨存取物件。
struct Node {
int data;
shared_ptr<Node> next; // 擁有權:下一節點
weak_ptr<Node> prev; // 非擁有權:上一節點
};
void useWeak() {
auto n1 = make_shared<Node>();
auto n2 = make_shared<Node>();
n1->next = n2;
n2->prev = n1; // weak_ptr 不增加計數
// 存取 weak_ptr 需轉為 shared_ptr (lock)
if (auto p = n2->prev.lock()) {
cout << "prev data: " << p->data << endl;
}
} // 正常釋放,計數歸零
shared_ptr 預設用 delete 釋放。管理非 new 分配資源(檔案控制代碼、C 風格陣列、malloc 記憶體、Windows HANDLE、OpenGL 物件等)時,需提供自定義刪除器。
可呼叫物件:函數指標、Lambda、仿函數 (functor)、std::function。
// 管理 FILE*
auto fp = shared_ptr<FILE>(fopen("data.txt", "w"), [](FILE* f){ fclose(f); });
// 管理 malloc 記憶體
auto buf = shared_ptr<void>(malloc(1024), [](void* p){ free(p); });
// 管理 C 風格陣列 (需配合 delete[])
auto arr = shared_ptr<int>(new int[10], [](int* p){ delete[] p; });
// 預設刪除器
struct DefaultDelete {
template <typename T>
void operator()(T* p) const { delete p; }
};
// 檔案關閉刪除器
struct Fclose {
void operator()(FILE* f) const { if (f) fclose(f); }
};
// free 刪除器
struct Free {
void operator()(void* p) const { free(p); }
};
// 簡易 shared_ptr 模擬 (教學用)
template <typename T, typename Deleter = DefaultDelete>
class SharedPtr {
T* ptr;
int* count;
Deleter del;
public:
SharedPtr(T* p = nullptr) : ptr(p), count(new int(1)), del() {}
~SharedPtr() { if (--*count == 0) { del(ptr); delete count; } }
// 複製/移動/指派... 略
};
// 使用
SharedPtr<FILE, Fclose> fp(fopen("log.txt", "w")); // 離開作用域自動 fclose
SharedPtr<int, Free> buf((int*)malloc(100)); // 離開作用域自動 free
shared_ptr,**雙向/父子雙向**必須一端改 weak_ptr。make_shared 優於 new:單次配置控制區塊+物件、例外安全。shared_ptr 不可互指派。shared_ptr<T[]> (C++17 支援),舊標準用 shared_ptr<T>(new T[n], [](T* p){delete[] p;})。weak_ptr 觀察者模式、快取、打破循環三大用途。