跳到主要内容

std::allocate_shared, std::allocate_shared_for_overwrite

定义于头文件 <memory>

声明

自 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 );

构造一个类型为 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) 进行初始化,其中类型为 A2a2 是已重新绑定到管理类型为 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) 相同(如果 TU[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_thisstd::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)

std::allocate_shared, std::allocate_shared_for_overwrite

定义于头文件 <memory>

声明

自 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 );

构造一个类型为 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) 进行初始化,其中类型为 A2a2 是已重新绑定到管理类型为 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) 相同(如果 TU[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_thisstd::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)