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 | - | 用于初始化数组中每个元素的初始值 |
[编辑] 返回值
指向 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) |
|
(直到 C++17) |
构造函数使用指针 ptr
启用 shared_from_this
,类型为 U*
,意味着它确定 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 起,此测试是必需的。
特性测试 宏 | 值 | 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_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++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
LWG 4024 | C++20 | 不清楚在std::make_shared_for_overwrite 中构造的对象是如何销毁的 |
已明确 |
[编辑] 参见
构造新的 shared_ptr (公共成员函数) | |
创建管理使用分配器分配的新对象的共享指针 (函数模板) | |
(C++11) |
允许对象创建指向自身的 shared_ptr (类模板) |
(C++14)(C++20) |
创建管理新对象的唯一指针 (函数模板) |
分配函数 (函数) |