std::make_shared, std::make_shared_for_overwrite
| 在標頭 <memory> 定義
|
||
| |
(1) | (C++11 起) |
| (2) | (C++20 起) | |
| |
(3) | (C++20 起) |
| |
(4) | (C++20 起) |
| |
(5) | (C++20 起) |
| (6) | (C++20 起) | |
| |
(7) | (C++20 起) |
為某個對象分配內存並以提供的實參初始化該對象。返回管理新創建的對象的 std::shared_ptr 對象。
T 類型,並如同以 ::new (pv) T(std::forward<Args>(args)...) 構造,其中 pv 是指向適合持有 T 類型對象的存儲的 void* 指針。如果該對象要被銷毀,那麼它會如同以 pt->~T() 被銷毀,其中 pt 是指向該 T 類型對象的指針。
|
此重載只有在 |
(C++20 起) |
std::remove_extent_t<T>[N] 類型。每個元素都具有默認的初始值。T 是無邊界的數組類型時才會參與重載決議。T 類型。每個元素都具有默認的初始值。T 是有邊界的數組類型時才會參與重載決議。std::remove_extent_t<T>[N] 類型。每個元素都具有初始值 u。T 是無邊界的數組類型時才會參與重載決議。T 類型。每個元素都具有初始值 u。T 是有邊界的數組類型時才會參與重載決議。T 類型。
- 如果
T不是數組類型,那麼如同以::new (pv) T構造該對象,其中pv是指向適合持有T類型對象的存儲的void*指針。如果該對象要被銷毀,那麼它會如同以pt->~T()被銷毀,其中pt是指向該T類型對象的指針。 - 如果
T是有邊界的數組類型,那麼不指定每個元素的初始值。
T 不是數組類型,或者是有邊界的數組類型時才會參與重載決議。std::remove_extent_t<T>[N] 類型。不指定每個元素的初始值。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 | - | 用以初始化數組每個元素的初值 |
返回值
指向具有 T 類型或在 T 是無邊界的數組類型時具有 std::remove_extent_t<T>[N] 類型(C++20 起)的對象的 std::shared_ptr。
對於返回的 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)較大時這可能是不想要的行為。 - 如果在可訪問
T的非公開構造函數的語境中執行,那麼std::shared_ptr<T>(new T(args...))可能會調用它,而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 是否擁有作為 std::enable_shared_from_this 特化的無歧義且可訪問(C++17 起)基類,在是的情況下會求值
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
{
// < 需要构造函数 (C++20 前)
C(int i) : i(i) {}
C(int i, float f) : i(i), f(f) {}
int i;
float f{};
};
int main()
{
// 为 “sp1” 的类型使用 “auto”
auto sp1 = std::make_shared<C>(1); // 重载 (1)
static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>);
std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n";
// 明确 “sp2” 的类型
std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // 重载 (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";
// 指向值初始化的 float[64] 的 shared_ptr;重载 (2):
std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64);
// 指向值初始化的 long[5][3][4] 的 shared_ptr;重载 (2):
std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5);
// 指向值初始化的 short[128] 的 shared_ptr;重载 (3):
std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>();
// 指向值初始化的 int[7][6][5] 的 shared_ptr;重载 (3):
std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>();
// 指向 double[256] 的 shared_ptr,其各元素均为 2.0;重载 (4):
std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0);
// 指向 double[7][2] 的 shared_ptr,其各 double[2] 元素均为 {3.0, 4.0};重载 (4):
std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0});
// 指向 vector<int>[4] 的 shared_ptr,其各向量的内容均为 {5, 6};重载 (4):
std::shared_ptr<std::vector<int>[]> sp9 =
std::make_shared<std::vector<int>[]>(4, {5, 6});
// 指向 float[512] 的 shared_ptr,其各元素均为 1.0;重载 (5):
std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0);
// 指向 double[6][2] 的 shared_ptr,其各 double[2] 元素均为 {1.0, 2.0};重载 (5):
std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0});
// 指向 vector<int>[4] 的 shared_ptr,其各向量的内容均为 {5, 6};重载 (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 中構造的對象
|
使之明確 |
參閱
構造新的 shared_ptr (公開成員函數) | |
| 創建管理一個用分配器分配的新對象的共享指針 (函數模板) | |
(C++11) |
允許對象創建指代自身的 shared_ptr (類模板) |
(C++14)(C++20) |
創建管理一個新對象的獨占指針 (函數模板) |
| 分配函數 (函數) |