std::make_shared, std::make_shared_for_overwrite
来自 cppreference.com
< cpp | memory | shared ptr
定义在头文件 <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 的数组。数组元素以其地址的升序进行初始化,当其生命周期结束时,它们以其原始构造的相反顺序被销毁。
在每种情况下,(如果 T 是数组类型,则为各个元素)(自 C++20 起) 对象将使用 p->~X() 销毁,其中 p 是指向该对象的指针,而 X 是其类型。
内容 |
[edit] 参数
args | - | 用于构造 T 实例的参数列表 |
N | - | 要使用的数组大小 |
u | - | 用于初始化数组每个元素的初始值 |
[edit] 返回值
类型为 T 的实例的 std::shared_ptr。
[edit] 异常
可能抛出 std::bad_alloc 或 T 构造函数抛出的任何异常。如果抛出异常,这些函数不会产生任何效果。 如果在数组构造期间抛出异常,则已初始化的元素将以反向顺序销毁。(自 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) |
|
(直到 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_this 是 std::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_overwrite、std::make_shared_for_overwrite 、std::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 (公有成员函数) | |
创建一个共享指针,该指针管理使用分配器分配的新对象 (函数模板) | |
(C++11) |
允许对象创建一个引用自身的 shared_ptr (类模板) |
(C++14)(C++20) |
创建一个管理新对象的唯一指针 (函数模板) |
分配函数 (函数) |