命名空间
变体
操作

std::make_shared, std::make_shared_for_overwrite

来自 cppreference.com
< cpp‎ | memory‎ | shared ptr
 
 
工具库
语言支持
类型支持 (基本类型,RTTI)
库功能测试宏 (C++20)
动态内存管理
程序工具
协程支持 (C++20)
可变参数函数
调试支持
(C++26)
三方比较
(C++20)
(C++20)(C++20)(C++20)
(C++20)(C++20)(C++20)
通用工具
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中已弃用)
整数比较函数
(C++20)(C++20)(C++20)   
(C++20)
交换类型操作
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
通用词汇类型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
基本字符串转换
(C++17)
(C++17)

 
动态内存管理
未初始化内存算法
受限的未初始化内存算法
分配器
垃圾回收支持
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)



 
 
定义在头文件 <memory>
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
(1) (自 C++11 起)
(T 不是数组)
template< class T >
shared_ptr<T> make_shared( std::size_t N );
(2) (自 C++20 起)
(T 是 U[])
template< class T >
shared_ptr<T> make_shared();
(3) (自 C++20 起)
(T 是 U[N])
template< class T >
shared_ptr<T> make_shared( std::size_t N, const std::remove_extent_t<T>& u );
(4) (自 C++20 起)
(T 是 U[])
template< class T >
shared_ptr<T> make_shared( const std::remove_extent_t<T>& u );
(5) (自 C++20 起)
(T 是 U[N])
template< class T >
shared_ptr<T> make_shared_for_overwrite();
(6) (自 C++20 起)
(T 不是 U[])
template< class T >
shared_ptr<T> make_shared_for_overwrite( std::size_t N );
(7) (自 C++20 起)
(T 是 U[])
1) 使用 args 作为 T 类型构造函数的参数列表,构造一个类型为 T 的对象,并将其包装在一个 std::shared_ptr 中。该对象使用表达式 ::new (pv) T(std::forward<Args>(args)...) 进行构造,其中 pv 是一个指向存储空间的内部 void* 指针,该存储空间适合保存类型为 T 的对象。该存储空间通常大于 sizeof(T),以便对共享指针的控制块和 T 对象使用一次分配。由该函数调用的 std::shared_ptr 构造函数使用指向新构造的类型为 T 的对象的指针启用 shared_from_this

仅当 T 不是数组类型时,此重载才参与重载解析。

(自 C++20 起)
2,3)(1) 相同,但构造的对象是一个可能多维的数组,其类型为 std::remove_all_extents_t<T> 的非数组元素使用就地 new 表达式 ::new(pv) std::remove_all_extents_t<T>() 进行值初始化。重载 (2) 在第一维创建一个大小为 N 的数组。数组元素以其地址的升序进行初始化,当其生命周期结束时,它们以其原始构造的相反顺序被销毁。
4,5)(2,3) 相同,但每个元素都使用默认值 u 进行初始化。如果 U 不是数组类型,则使用与 (1) 中相同的就地 new 表达式执行此操作;否则,使用与 (1) 中相同的就地 new 表达式执行此操作,就好像使用来自 u 的对应元素初始化(可能多维)数组的每个非数组元素一样。重载 (4) 在第一维创建一个大小为 N 的数组。数组元素以其地址的升序进行初始化,当其生命周期结束时,它们以其原始构造的相反顺序被销毁。
6) 如果 T 不是数组类型,则与 (1) 相同,如果 TU[N],则与 (3) 相同,不同之处在于所创建的对象是 默认初始化 的。
7)(2) 相同,不同之处在于各个数组元素是 默认初始化 的。

在每种情况下,(如果 T 是数组类型,则为各个元素)(自 C++20 起) 对象将使用 p->~X() 销毁,其中 p 是指向该对象的指针,而 X 是其类型。

内容

[edit] 参数

args - 用于构造 T 实例的参数列表
N - 要使用的数组大小
u - 用于初始化数组每个元素的初始值

[edit] 返回值

类型为 T 的实例的 std::shared_ptr

[edit] 异常

可能抛出 std::bad_allocT 构造函数抛出的任何异常。如果抛出异常,这些函数不会产生任何效果。 如果在数组构造期间抛出异常,则已初始化的元素将以反向顺序销毁。(自 C++20 起)

[edit] 备注

此函数可以用作 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()) 的代码可能会导致内存泄漏,如果在 new int(42) 之后调用 g 并抛出异常,而 f(std::make_shared<int>(42), g()) 是安全的,因为两次函数调用 永远不会交错
(直到 C++17)

一个构造函数启用 shared_from_this,使用类型为 U* 的指针 ptr,意味着它确定 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_thisstd::enable_shared_from_this 的隐藏的可变 std::weak_ptr 成员。对 weak_this 成员的赋值不是原子的,并且与对同一对象的任何潜在并发访问冲突。这确保了将来对 shared_from_this() 的调用将与使用此原始指针构造函数创建的 std::shared_ptr 共享所有权。

上述解释代码中的测试 ptr->weak_this.expired() 确保如果 weak_this 已经指示所有者,则不会重新分配它。自 C++17 起,需要此测试。

特性测试 Std 特性
__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_overwritestd::make_shared_for_overwritestd::make_unique_for_overwrite);重载 (6,7)

[edit] 示例

#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 }

[edit] 另请参见

构造新的 shared_ptr
(公有成员函数) [edit]
创建一个共享指针,该指针管理使用分配器分配的新对象
(函数模板) [edit]
允许对象创建一个引用自身的 shared_ptr
(类模板) [edit]
创建一个管理新对象的唯一指针
(函数模板) [编辑]
分配函数
(函数) [编辑]