Namespaces
Variants

std:: make_shared, std:: make_shared_for_overwrite

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
定义于头文件 <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 是指向能容纳 T 类型对象的存储空间的 void * 类型指针。若需销毁该对象,则销毁方式相当于执行 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 是指向能容纳 T 类型对象的存储空间的 void * 指针。若需销毁该对象,将以 pt - > ~T ( ) 的方式销毁,其中 pt 是指向该 T 类型对象的指针。
  • T 是有界数组类型,每个元素的初始值未指定。
仅当 T 不是数组类型或为有界数组类型时,此重载才会参与重载决议。
7) 该对象的类型为 std:: remove_extent_t < T > [ N ] 。每个元素的初始值未指定。
仅当 T 为无边界数组类型时,此重载才会参与重载决议。

目录

数组元素的初始化与销毁

类型为 U 的数组元素按其地址升序进行初始化。

  • U 不是数组类型,每个元素的构造方式如下列表达式所示,其中 pv 是指向能容纳 U 类型对象的存储空间的 void * 指针:
2,3) :: new ( pv ) U ( )
4,5) :: new ( pv ) U ( u )
6,7) :: new ( pv ) U
  • 否则,递归初始化每个元素的子元素。对于下一维度:

当返回的 std::shared_ptr 所管理对象的生命周期结束时,或当数组元素的初始化抛出异常时,已初始化的元素将按其原始构造顺序的逆序进行销毁。

对于每个待销毁的非数组类型 U 的数组元素,其销毁方式为 pu - > ~U ( ) ,其中 pu 是指向该 U 类型数组元素的指针。

(since C++20)

参数

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

返回值

指向 T 类型对象的 std::shared_ptr ,或者指向 std:: remove_extent_t < T > [ N ] 如果 T 是无边界数组类型 (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)
  • 诸如 f ( std:: shared_ptr < int > ( new int ( 42 ) ) , g ( ) ) 的代码可能导致内存泄漏:若 g new 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
{
    // 需要构造函数(直至 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,其中每个 vector
    // 包含内容 {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]

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 适用范围 发布时的行为 正确行为
LWG 4024 C++20 不清楚在
std::make_shared_for_overwrite 中构造的对象如何被销毁
已明确说明

参见

构造新的 shared_ptr
(公开成员函数)
创建管理使用分配器分配的新对象的共享指针
(函数模板)
允许对象创建指向自身的 shared_ptr
(类模板)
创建管理新对象的唯一指针
(函数模板)
分配函数
(函数)