std::allocate_shared, std::allocate_shared_for_overwrite
定义于头文件 <memory>
。
声明
- T 是 U[]
- T 不是 U[]
- T 是非数组
自 C++20 起
// 2)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N );
// 3)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc );
// 4)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N,
const std::remove_extent_t<T>& u );
// 5)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc,
const std::remove_extent_t<T>& u );
// 7)
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc, std::size_t N );
自 C++20 起
// 6)
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc );
// 1)
template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );
构造一个类型为 T
的对象,并使用 args
作为 T
的构造函数的参数列表将其包装在 std::shared_ptr
中。该对象按照以下表达式构造:
::new (pv) T(v)
(直到 C++20)std::allocator_traits<A2>::construct(a, pv, v)
(C++20 起),
其中 pv
是一个内部的 void*
指针,指向适合容纳类型为 T
的对象的存储空间,a 是一个复制的分配器,已重新绑定到 std::remove_cv_t<T>
。存储空间通常比 sizeof(T)
大,以便对共享指针的控制块和 T
对象使用一次分配。此函数调用的 std::shared_ptr
构造函数启用 shared_from_this
,并指向新构造的类型为 T
的对象。
所有内存分配都使用 alloc
的副本进行,alloc
必须满足 Allocator
的要求。
此重载仅在 T
*不是* 数组类型时参与重载解析。
2,3)
与 (1) 相同,但构造的对象是一个可能的 N 维数组,其每个非数组元素都通过表达式 std::allocator_traits<A2>::construct(a2, pv)
进行初始化,其中类型为 A2
的 a2
是已重新绑定到管理类型为 std::remove_cv_t<std::remove_all_extents_t<T>>
对象的分配器的副本。
重载 (2) 创建一个沿第一个维度大小为 N
的数组。数组元素按地址升序初始化,在其生命周期结束时按原始构造的相反顺序销毁。
4,5)
与 (2,3) 相同,但数组元素使用默认值 u
进行初始化。如果 std::remove_extent_t<T>
本身不是数组类型,则执行方式与 (1) 中的相同分配器表达式相同,只是分配器已重新绑定到 std::remove_cv_t<std::remove_all_extents_t<T>>
。
否则,将执行方式与使用 (1) 中的相同分配器表达式,通过将 (可能的 N 维) 数组的每个非数组元素与 u
中的相应元素初始化来进行,只是分配器已重新绑定到类型 std::remove_cv_t<std::remove_all_extents_t<T>>
。
重载 (4) 创建一个沿第一个维度大小为 N
的数组。数组元素按地址升序初始化,在其生命周期结束时按原始构造的相反顺序销毁。
与 (1) 相同(如果 T
不是数组类型)和 (3) 相同(如果 T
是 U[N]
),不同之处在于创建的对象是默认初始化的。
与 (2) 相同,不同之处在于单个数组元素是默认初始化的。
对于 allocate_shared
,对象(或 (2-5) 的单个数组元素 (C++20 起))通过表达式 std::allocator_traits<A2>::destroy(a, p)
进行销毁,其中 p
是指向对象的指针,a 是传递给 allocate_shared
的分配器的副本,已重新绑定到正在销毁的对象的类型。
对于 allocate_shared_for_overwrite
,对象(或 T
是数组类型时的单个元素)将通过 p->~X()
进行销毁,其中 p
是指向对象的指针,X
是其类型。(C++20 起)
参数
alloc
- 要使用的 Allocator
。
args..
. - 用于构造 T
实例的参数列表。
N
- 要使用的数组大小
u
- 用于初始化数组每个元素的初始值
返回值
类型为 T
的实例的 std::shared_ptr
。
异常
可以抛出从 Alloc::allocate()
或 T
的构造函数抛出的异常。如果抛出异常,(1) 无效。
如果在数组构造期间抛出异常,已初始化的元素将按相反顺序销毁 (C++20 起)
备注
与 std::make_shared
类似,此函数通常只执行一次内存分配,并将 T
对象和控制块都放置在分配的内存块中(标准推荐但不强制要求这样做,所有已知实现都这样做)。alloc
的副本作为控制块的一部分存储,以便在共享和弱引用计数都达到零时用于释放它。
与 std::shared_ptr
构造函数不同,std::allocate_shared
不接受单独的自定义删除器:提供的分配器用于销毁控制块和 T
对象,以及释放它们的共享内存块。
std::shared_ptr
支持数组类型(截至 C++17),但 std::allocate_shared
不支持。此功能由 boost::allocate_shared
支持。(直到 C++20)
构造函数通过指针 ptr
类型为 U*
启用 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
是 std::enable_shared_from_this
的隐藏可变 std::weak_ptr
成员。对 weak_this
成员的赋值不是原子的,并且与对同一对象的任何潜在并发访问冲突。这确保将来对 shared_from_this()
的调用将与此原始指针构造函数创建的 std::shared_ptr
共享所有权。
示例代码中的测试 ptr->weak_this.expired()
确保在 weak_this
尚未指向所有者时才重新分配它。此测试是 C++17 起所必需的。
特性测试宏 | 注释 |
---|---|
__cpp_lib_smart_ptr_for_overwrite | 对于重载 (6,7) |