命名空间
变体
操作

std::allocate_shared, std::allocate_shared_for_overwrite

来自 cppreference.cn
< cpp‎ | 内存‎ | 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*)
显式生命周期管理
 
 
定义于头文件 <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_ptr,若 T 为无界数组类型,则为 std::remove_extent_t<T>[N](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 起是必需的。

特性测试 标准 特性
__cpp_lib_smart_ptr_for_overwrite 202002L (C++20) 使用默认初始化创建智能指针(std::allocate_shared_for_overwritestd::make_shared_for_overwritestd::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++ 标准。

缺陷报告 应用于 发布时的行为 正确的行为
LWG 3216 C++20 std::allocate_shared 在构造和销毁对象前总是重绑定
分配器
重绑定是可选的
LWG 4024 C++20 不清楚在 std::allocate_shared_for_overwrite
构造的对象如何被销毁
已明确

[编辑] 参阅

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