視頻教程:https://www.bilibili.com/video/av86947941
shared_ptr維護引用計數(shù)需要的信息
- 強引用, 用來記錄當前有多少個存活的 shared_ptrs 正持有該對象. 共享的對象會在最后一個強引用離開的時候銷毀( 也可能釋放).
- 弱引用, 用來記錄當前有多少個正在觀察該對象的 weak_ptrs. 當最后一個弱引用離開的時候, 共享的內(nèi)部信息控制塊會被銷毀和釋放 (共享的對象也會被釋放, 如果還沒有釋放的話).
使用原始的new函數(shù)創(chuàng)建shared_ptr
- 首先是原始的new分配了原始對象, 然后將這個對象傳遞給 shared_ptr (即使用 shared_ptr 的構(gòu)造函數(shù)) , shared_ptr 對象只能單獨的分配控制塊。
- 控制塊包含被指向?qū)ο蟮囊糜嫈?shù)以及其他,也就是說,控制塊的內(nèi)存是在std::shared_ptr的構(gòu)造函數(shù)中分配的。

使用make_shared創(chuàng)建shared_ptr
- 如果選擇使用 make_shared 的話, 內(nèi)存分配的動作, 可以一次性完成,因為std::make_shared申請一個單獨的內(nèi)存塊來同時存放指向的對象和控制塊,這減少了內(nèi)存分配的次數(shù), 而內(nèi)存分配是代價很高的操作。
- 同時,使用std::make_shared消除了一些控制塊需要記錄的信息,減少了程序的總內(nèi)存占用。

make_shared實現(xiàn)異常安全
- 在shared_ptr的使用過程中,不能在函數(shù)實參中創(chuàng)建shared_ptr,如下:
//Define
void F(const std::shared_ptr<Lhs>& lhs, const std::shared_ptr<Rhs>& rhs)
{
;
}
//Call
F(std::shared_ptr<Lhs>(new Lhs("foo")),std::shared_ptr<Rhs>(new Rhs("bar")));
C++ 是不保證參數(shù)求值順序, 以及內(nèi)部表達式的求值順序的, 所以可能的執(zhí)行順序如下:
new Lhs(“foo”))
new Rhs(“bar”))
std::shared_ptr<Lhs>
std::shared_ptr<Rhs>
如果在第2步的時候,發(fā)生了異常,第一步申請的 Lhs 對象內(nèi)存就泄露了,
產(chǎn)生這個問題的核心在于, shared_ptr 沒有立即獲得裸指針,所以就有可能產(chǎn)生內(nèi)存泄漏。當然,這個問題是可以這樣解決:
auto lhs = std::shared_ptr<Lhs>(new Lhs("foo"));
auto rhs = std::shared_ptr<Rhs>(new Rhs("bar"));
F(lhs, rhs);
但,最推薦的做法是
F(std::make_shared<Lhs>("foo"), std::make_shared<Rhs>("bar"));
因為,申請原始對象和將原始對象裸指針賦值給shared_ptr是在同一個執(zhí)行序列里,失敗的話一起失敗,成功就一起成功,這樣就能保住創(chuàng)建的原始對象裸指針能安全的存放到std::shared_ptr中
使用make_shared的缺點
- 創(chuàng)建的對象如果沒有公有的構(gòu)造函數(shù)時,make_shared無法使用。
- 使用make_shared內(nèi)存可能無法及時回收,對內(nèi)存要求要的場景需要注意。