名稱空間
變體
操作

std::make_shared, std::make_shared_for_overwrite

來自 cppreference.com
 
 
記憶體管理庫
(僅作說明*)
未初始化記憶體演算法
(C++17)
(C++17)
(C++17)
受約束的未初始化
記憶體演算法
C 庫

分配器
記憶體資源
垃圾回收支援
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
未初始化儲存
(直到 C++20*)
(直到 C++20*)
顯式生命週期管理
 
 
定義於標頭檔案 <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 物件。

1) 物件型別為 T,其構造方式等同於 ::new (pv) T(std::forward<Args>(args)...),其中 pv 是一個 void* 指標,指向足以容納型別 T 物件的儲存空間。如果物件要被銷燬,其銷燬方式等同於 pt->~T(),其中 pt 是指向該 T 型別物件的指標。

此過載僅在 T 不是陣列型別時參與過載決議。

(C++20 起)
2) 物件型別為 std::remove_extent_t<T>[N]。每個元素都有一個預設初始值。
此過載僅在 T 是無界陣列型別時參與過載決議。
3) 物件型別為 T。每個元素都有一個預設初始值。
此過載僅在 T 是有界陣列型別時參與過載決議。
4) 物件型別為 std::remove_extent_t<T>[N]。每個元素都具有初始值 u
此過載僅在 T 是無界陣列型別時參與過載決議。
5) 物件型別為 T。每個元素都具有初始值 u
此過載僅在 T 是有界陣列型別時參與過載決議。
6) 物件型別為 T
  • 如果 T 不是陣列型別,則物件的構造方式等同於 ::new (pv) T,其中 pv 是一個 void* 指標,指向足以容納型別 T 物件的儲存空間。如果物件要被銷燬,其銷燬方式等同於 pt->~T(),其中 pt 是指向該 T 型別物件的指標。
  • 如果 T 是有界陣列型別,則每個元素的初始值未指定。
此過載僅在 T 不是陣列型別或是有界陣列型別時參與過載決議。
7) 物件型別為 std::remove_extent_t<T>[N]。每個元素的初始值未指定。
此過載僅在 T 是無界陣列型別時參與過載決議。

目錄

初始化和銷燬陣列元素

型別為 U 的陣列元素按其地址的升序進行初始化。

  • 如果 U 不是陣列型別,則每個元素的構造方式等同於以下表達式,其中 pv 是一個 void* 指標,指向足以容納型別 U 物件的儲存空間
2,3) ::new (pv) U()
4,5) ::new (pv) U(u)
6,7) ::new (pv) U
  • 否則,遞迴初始化每個元素的元素。對於下一維度

當由返回的 std::shared_ptr 管理的物件的生命週期結束時,或者當陣列元素的初始化丟擲異常時,已初始化的元素將按其原始構造的逆序被銷燬。

對於每個要銷燬的非陣列型別 U 的陣列元素,其銷燬方式等同於 pu->~U(),其中 pu 是指向該 U 型別陣列元素的指標。

(C++20 起)

[編輯] 引數

args - 用於構造 T 型別物件的引數列表
N - 要使用的陣列大小
u - 用於初始化陣列每個元素的初始值

[編輯] 返回值

std::shared_ptr 指向型別為 T 的物件,如果 T 是無界陣列型別,則指向 std::remove_extent_t<T>[N](C++20起)

對於返回的 std::shared_ptr rr.get() 返回非空指標,r.use_count() 返回 1

[編輯] 異常

可能丟擲 std::bad_allocT 的建構函式丟擲的任何異常。如果丟擲異常,函式無效。如果陣列構造期間丟擲異常,已初始化的元素將按逆序銷燬。(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 前)
  • 諸如 f(std::shared_ptr<int>(new int(42)), g()) 的程式碼可能會導致記憶體洩漏,如果 gnew int(42) 之後被呼叫並丟擲異常,而 f(std::make_shared<int>(42), g()) 是安全的,因為兩個函式呼叫 從不交錯
(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
(公共成員函式) [編輯]
建立一個共享指標,該指標管理使用分配器分配的新物件
(函式模板) [編輯]
允許物件建立指向自身的 shared_ptr
(類模板) [編輯]
建立一個管理新物件的唯一指標
(函式模板) [編輯]
分配函式
(函式) [編輯]