std::allocate_shared, std::allocate_shared_for_overwrite

来自cppreference.com
< cpp‎ | memory‎ | shared ptr
 
 
内存管理库
(仅用于阐述*)
分配器
未初始化内存算法
受约束的未初始化内存算法
内存资源
未初始化存储 (C++20 前)
(C++17 弃用)
(C++17 弃用)

垃圾收集器支持 (C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
 
 
在标头 <memory> 定义
template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );
(1) (C++11 起)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N );
(2) (C++20 起)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc );
(3) (C++20 起)
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N,

                               const std::remove_extent_t<T>& u );
(4) (C++20 起)
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc,

                               const std::remove_extent_t<T>& u );
(5) (C++20 起)
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc );
(6) (C++20 起)
template< class T, class Alloc >

shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc,

                                             std::size_t N );
(7) (C++20 起)

使用 alloc 的(重绑到某个未指定的 value_type 的)副本为某个对象分配内存并以提供的实参初始化该对象。返回管理新创建的对象的 std::shared_ptr 对象。

1) 该对象具有 T 类型,并如同以 std::allocator_traits<Alloc>::construct
    (a, pt, (std::forward<Args>(args)...)
构造,其中 pt 是指向适合持有 std::remove_cv_t<T> 类型对象的存储的 std::remove_cv_t<T>* 指针。如果该对象要被销毁,那么它会如同以 std::allocator_traits<Alloc>::destroy(a, pt) 被销毁,其中 pt 是指向该 std::remove_cv_t<T> 类型对象的指针。
在以上描述中,a 具有 Alloc 类型,并且它是 alloc 的潜在重绑副本。

此重载只有在 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 是无边界的数组类型时才会参与重载决议。

目录

初始化和销毁数组元素

在以下描述中,a 具有 Alloc 类型,并且它是 alloc 的潜在重绑副本。

U 类型的数组元素会以它们地址的升序进行初始化。

  • 如果 U 不是数组类型,那么每个元素如同以以下表达式构造,其中 pu 是指向适合持有 std::remove_cv_t<U> 类型对象的存储的 std::remove_cv_t<U>* 指针,且 pv 是指向适合持有 U 类型对象的存储的 void* 指针:
2,3) std::allocator_traits<Alloc>::construct(a, pu)
4,5) std::allocator_traits<Alloc>::construct(a, pu, u)
6,7) ::new (pv) U
  • 否则递归地初始化每个元素各自的元素。对于数组的下一维度:

当返回的 std::shared_ptr 管理的对象的生存期结束,或初始化数组元素时抛出异常,那么已初始化的元素会按构造时的逆序销毁。

对于每一个要被销毁的数组元素,它如同以以下表达式被销毁:

2-5) std::allocator_traits<Alloc>::destroy(a, pu),其中 pu 是指向该 U 类型数组元素的 U* 指针
6,7) pu->~U(),其中 pu 是指向该 U 类型数组元素的指针
(C++20 起)

[编辑] 参数

alloc - 使用的分配器
args... - 构造 T 实例将要用到的实参列表
N - 所用的数组大小
u - 用以初始化数组每个元素的初值

[编辑] 返回值

指向具有 T 类型或在 T 是无边界的数组类型时具有 std::remove_extent_t<T>[N] 类型(C++20 起)的对象的 std::shared_ptr

对于返回的 std::shared_ptr rr.get() 会返回非空指针,且 r.use_count() 会返回 1

[编辑] 异常

能抛出从 Alloc::allocate() 抛出的异常,或从 T 构造函数抛出的异常。若抛出异常,则 (1) 无效果。若异常在数组的构造中抛出,则已初始化元素以逆序销毁。(C++20 起)

[编辑] 注解

这些函数通常会分配多于 sizeof(T) 的内存以储存内部记录结构,例如引用计数。

类似 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 前)

构造函数以 U* 类型指针 ptr 启用 shared_from_this,表示它确定 U 是否拥有作为 std::enable_shared_from_this 特化的无歧义且可访问(C++17 起)基类,在是的情况下会求值 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_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 <cstddef>
#include <iostream>
#include <memory>
#include <memory_resource>
#include <vector>
 
class Value
{
    int i;
public:
    Value(int i) : i(i) { std::cout << "Value(), i = " << i << '\n'; }
    ~Value() { std::cout << "~Value(), i = " << i << '\n'; }
    void print() const { std::cout << "i = " << i << '\n'; }
};
 
int main()
{
    // 创建使用单调缓冲区资源的多态分配器
    std::byte buffer[sizeof(Value) * 8];
    std::pmr::monotonic_buffer_resource resource(buffer, sizeof(buffer));
    std::pmr::polymorphic_allocator<Value> allocator(&resource);
 
    std::vector<std::shared_ptr<Value>> v;
 
    for (int i{}; i != 4; ++i)
        // 以自定义分配器使用 std::allocate_shared
        v.emplace_back(std::allocate_shared<Value>(allocator, i));
 
    for (const auto& sp : v)
        sp->print();
} //< 全部共享指针都会在离开作用域使自动清理。

输出:

Value(), i = 0
Value(), i = 1
Value(), i = 2
Value(), i = 3
i = 0
i = 1
i = 2
i = 3
~Value(), i = 0
~Value(), i = 1
~Value(), i = 2
~Value(), i = 3

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 3216 C++20 std::allocate_shared 在构造和销毁对象前始终会重绑分配器 可以不重绑
LWG 4024 C++20 不明确如何销毁 std::allocate_shared_for_overwrite 中构造的对象 使之明确

[编辑] 参阅

构造新的 shared_ptr
(公开成员函数) [编辑]
创建管理一个新对象的共享指针
(函数模板) [编辑]