std::make_shared, std::make_shared_for_overwrite
定義於標頭檔案 <memory> |
||
template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args ); |
(1) | (C++11 起) |
template< class T > shared_ptr<T> make_shared( std::size_t N ); |
(2) | (C++20 起) |
template< class T > shared_ptr<T> make_shared(); |
(3) | (C++20 起) |
template< class T > shared_ptr<T> make_shared( std::size_t N, const std::remove_extent_t<T>& u ); |
(4) | (C++20 起) |
template< class T > shared_ptr<T> make_shared( const std::remove_extent_t<T>& u ); |
(5) | (C++20 起) |
template< class T > shared_ptr<T> make_shared_for_overwrite(); |
(6) | (C++20 起) |
template< class T > shared_ptr<T> make_shared_for_overwrite( std::size_t N ); |
(7) | (C++20 起) |
分配物件記憶體並使用提供的引數初始化物件。返回一個管理新建立物件的 std::shared_ptr 物件。
T
,其構造方式等同於 ::new (pv) T(std::forward<Args>(args)...),其中 pv 是一個 void* 指標,指向足以容納型別 T
物件的儲存空間。如果物件要被銷燬,其銷燬方式等同於 pt->~T(),其中 pt 是指向該 T
型別物件的指標。
此過載僅在 |
(C++20 起) |
T
是無界陣列型別時參與過載決議。T
。每個元素都有一個預設初始值。T
是有界陣列型別時參與過載決議。T
是無界陣列型別時參與過載決議。T
。每個元素都具有初始值 u。T
是有界陣列型別時參與過載決議。T
。- 如果
T
不是陣列型別,則物件的構造方式等同於 ::new (pv) T,其中 pv 是一個 void* 指標,指向足以容納型別T
物件的儲存空間。如果物件要被銷燬,其銷燬方式等同於 pt->~T(),其中 pt 是指向該T
型別物件的指標。 - 如果
T
是有界陣列型別,則每個元素的初始值未指定。
T
不是陣列型別或是有界陣列型別時參與過載決議。T
是無界陣列型別時參與過載決議。
初始化和銷燬陣列元素型別為
2,3) ::new (pv) U()
4,5) ::new (pv) U(u)
6,7) ::new (pv) U
當由返回的 std::shared_ptr 管理的物件的生命週期結束時,或者當陣列元素的初始化丟擲異常時,已初始化的元素將按其原始構造的逆序被銷燬。 對於每個要銷燬的非陣列型別 |
(C++20 起) |
[編輯] 引數
args | - | 用於構造 T 型別物件的引數列表 |
N | - | 要使用的陣列大小 |
u | - | 用於初始化陣列每個元素的初始值 |
[編輯] 返回值
std::shared_ptr 指向型別為 T
的物件,如果 T
是無界陣列型別,則指向 std::remove_extent_t<T>[N](C++20起)。
對於返回的 std::shared_ptr r,r.get() 返回非空指標,r.use_count() 返回 1。
[編輯] 異常
可能丟擲 std::bad_alloc 或 T
的建構函式丟擲的任何異常。如果丟擲異常,函式無效。如果陣列構造期間丟擲異常,已初始化的元素將按逆序銷燬。(C++20起)
[編輯] 注意
這些函式通常會分配比 sizeof(T) 更多的記憶體,以用於內部簿記結構,例如引用計數。
這些函式可以作為 std::shared_ptr<T>(new T(args...)) 的替代品。其權衡在於:
- std::shared_ptr<T>(new T(args...)) 執行至少兩次分配(一次用於物件
T
,一次用於共享指標的控制塊),而 std::make_shared<T> 通常只執行一次分配(標準推薦但不要求這樣做;所有已知實現都這樣做)。 - 如果所有共享所有者的生命週期結束後,有任何 std::weak_ptr 引用由
std::make_shared
建立的控制塊,則T
佔用的記憶體將持續存在,直到所有弱所有者也被銷燬,如果 sizeof(T) 很大,這可能是不可取的。 - std::shared_ptr<T>(new T(args...)) 如果在可訪問的上下文中執行,可能會呼叫
T
的非公共建構函式,而std::make_shared
需要公共訪問所選的建構函式。 - 與 std::shared_ptr 建構函式不同,
std::make_shared
不允許自定義刪除器。 -
std::make_shared
使用 ::new,因此如果已使用類特定的 operator new 設定了任何特殊行為,它將與 std::shared_ptr<T>(new T(args...)) 不同。
|
(C++20 前) |
|
(C++17 前) |
一個建構函式透過型別為 U*
的指標 ptr 啟用 shared_from_this
意味著它確定 U
是否有一個明確且可訪問的(C++17起)基類,該基類是 std::enable_shared_from_this 的特化,如果是,則建構函式評估 if (ptr != nullptr && ptr->weak_this
.expired())
ptr->weak_this
= std::shared_ptr<std::remove_cv_t<U>>
(*this, const_cast<std::remove_cv_t<U>*>(ptr)); 。
對 weak_this
的賦值不是原子的,並且與任何可能併發訪問同一物件的行為衝突。這確保了未來對 shared_from_this() 的呼叫將與此裸指標建構函式建立的 std::shared_ptr 共享所有權。
上述程式碼中的測試 ptr->weak_this
.expired() 確保如果 weak_this
已經指示了一個所有者,則不會重新賦值。C++17 起要求此測試。
特性測試宏 | 值 | 標準 | 特性 |
---|---|---|---|
__cpp_lib_shared_ptr_arrays |
201707L |
(C++20) | std::make_shared 的陣列支援;過載 (2-5) |
__cpp_lib_smart_ptr_for_overwrite |
202002L |
(C++20) | 預設初始化智慧指標建立 (std::allocate_shared_for_overwrite, std::make_shared_for_overwrite , std::make_unique_for_overwrite);過載 (6,7) |
[編輯] 示例
#include <iostream> #include <memory> #include <type_traits> #include <vector> struct C { // constructors needed (until C++20) C(int i) : i(i) {} C(int i, float f) : i(i), f(f) {} int i; float f{}; }; int main() { // using “auto” for the type of “sp1” auto sp1 = std::make_shared<C>(1); // overload (1) static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>); std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n"; // being explicit with the type of “sp2” std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // overload (1) static_assert(std::is_same_v<decltype(sp2), std::shared_ptr<C>>); static_assert(std::is_same_v<decltype(sp1), decltype(sp2)>); std::cout << "sp2->{ i:" << sp2->i << ", f:" << sp2->f << " }\n"; // shared_ptr to a value-initialized float[64]; overload (2): std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64); // shared_ptr to a value-initialized long[5][3][4]; overload (2): std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5); // shared_ptr to a value-initialized short[128]; overload (3): std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>(); // shared_ptr to a value-initialized int[7][6][5]; overload (3): std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>(); // shared_ptr to a double[256], where each element is 2.0; overload (4): std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0); // shared_ptr to a double[7][2], where each double[2] // element is {3.0, 4.0}; overload (4): std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0}); // shared_ptr to a vector<int>[4], where each vector // has contents {5, 6}; overload (4): std::shared_ptr<std::vector<int>[]> sp9 = std::make_shared<std::vector<int>[]>(4, {5, 6}); // shared_ptr to a float[512], where each element is 1.0; overload (5): std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0); // shared_ptr to a double[6][2], where each double[2] element // is {1.0, 2.0}; overload (5): std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0}); // shared_ptr to a vector<int>[4], where each vector // has contents {5, 6}; overload (5): std::shared_ptr<std::vector<int>[4]> spC = std::make_shared<std::vector<int>[4]>({5, 6}); }
輸出
sp1->{ i:1, f:0 } sp2->{ i:2, f:3 }
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
LWG 4024 | C++20 | 在 std::make_shared_for_overwrite 中構造的物件如何銷燬尚不清楚std::make_shared_for_overwrite 中的物件是如何被銷燬的 |
已明確 |
[編輯] 另請參閱
構造新的 shared_ptr (公共成員函式) | |
建立一個共享指標,該指標管理使用分配器分配的新物件 (函式模板) | |
(C++11) |
允許物件建立指向自身的 shared_ptr (類模板) |
(C++14)(C++20) |
建立一個管理新物件的唯一指標 (函式模板) |
分配函式 (函式) |