命名空间
变体
操作

std::allocate_shared, std::allocate_shared_for_overwrite

来自 cppreference.cn
< cpp‎ | memory‎ | shared ptr
 
 
内存管理库
(仅为说明目的*)
未初始化内存算法
(C++17)
(C++17)
(C++17)
受约束的未初始化
内存算法
C 库

分配器
内存资源
垃圾回收支持
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
未初始化存储
(在 C++20 中弃用*)
(在 C++20 中弃用*)
(在 C++20 中弃用*)
显式生命周期管理
 
 
定义于头文件 <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 是一个 void* 指针,指向适合容纳 T 类型对象的存储。如果要销毁对象,则销毁方式如同 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 是一个 void* 指针,指向适合容纳 U 类型对象的存储
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 管理的对象的生命周期结束时,或者当数组元素的初始化抛出异常时,已初始化的元素将按其原始构造的相反顺序销毁。

对于要销毁的非数组类型 U 的每个数组元素,其销毁方式如同以下表达式

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

[编辑] 参数

alloc - 要使用的 Allocator
args... - 将用于构造 T 实例的参数列表
N - 要使用的数组大小
u - 用于初始化数组每个元素的初始值

[编辑] 返回值

指向 T 类型对象的 std::shared_ptrstd::remove_extent_t<T>[N],如果 T 是无界数组类型(自 C++20 起)

对于返回的 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 是否具有 明确且可访问的(自 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_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()
{
    // Create a polymorphic allocator using the monotonic buffer resource
    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)
        // Use std::allocate_shared with the custom allocator
        v.emplace_back(std::allocate_shared<Value>(allocator, i));
 
    for (const auto& sp : v)
        sp->print();
} //< All shared pointers will automatically clean up when they go out of scope.

输出

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++ 标准。

DR 应用于 已发布行为 正确行为
LWG 3216 C++20 std::allocate_shared 始终重新绑定
分配器,然后在构造和销毁对象之前
重新绑定是可选的
LWG 4024 C++20 不清楚在
std::allocate_shared_for_overwrite 中构造的对象是如何销毁的
已明确

[编辑] 参见

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