系統程式設計師的 C++

std::shared_ptr(共享所有權智慧指標)

有時一個物件真的有好幾個擁有者,而其中沒有任何一個知道誰會最後用完——想像一個被三個獨立子系統使用的共享快取項目,它應該活得恰好和「還有人需要它」一樣久。std::shared_ptr 透過計數有多少個擁有者,並只在最後一個離開時才 delete 物件來處理這件事。unique_ptr 說「恰好一個擁有者」,shared_ptr 則說「你要幾個都行,物件隨著最後一個一同消亡」。

它透過一個小小的、配置在堆積上的控制區塊(control block)運作,這個區塊緊鄰物件(或就在物件旁邊)。控制區塊持有一個強參考計數:複製一個 shared_ptr 使它加一,銷毀或重設一個使它減一,而當它歸零時,所管理的物件被銷毀,接著控制區塊被釋放。因此每個 shared_ptr 有兩個指標寬——一個指向物件,一個指向控制區塊——而計數更新是原子的,所以多個執行緒可以安全地複製與銷毀指向同一物件的 shared_ptr。你應該用 std::make_shared<T>(args...) 建立它,它把物件與其控制區塊一起在單次配置中分配,省下一趟堆積往返並改善區域性。

為何重要:shared_ptr 是真正共享所有權、以及生存期需要超出任何單一範圍時的工具。但它不是免費的,這是誠實的部分:原子參考計數操作比裸指標貴,控制區塊是額外記憶體,而且關鍵在於——兩個互相指向彼此的 shared_ptr 形成參考環,計數永遠到不了零,於是物件洩漏。打破這種環正是 std::weak_ptr 的工作。先伸手拿 unique_ptr;只在所有權真的是共享時才用 shared_ptr,而非把它當作偷懶的預設。

auto a = std::make_shared<Node>(); auto b = a; // 計數現在是 2;只有當 a 與 b 都消失時 Node 才被刪除

每次複製都使強計數加一;當計數降到零時物件的解構子才執行。

常見誤解:shared_ptr 不是隨插即用的「安全指標」——它的參考計數對計數本身是執行緒安全的,但被指向的物件並不會自動免於資料競爭,而兩個互相指向的 shared_ptr 會永遠洩漏。把它用於共享所有權,而非當作預設。

又稱
shared pointerreference-counted smart pointer共享所有權指標