Namespaces
Variants

std:: allocate_shared, std:: allocate_shared_for_overwrite

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until 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 不是数组类型时参与重载决议。

(since 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 所管理对象的生命周期结束时,或当数组元素的初始化抛出异常时,已初始化的元素按其原始构造顺序的逆序进行销毁。

对于每个待销毁的非数组类型 U 的数组元素,其销毁方式如下列表达式所示:

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 - 用于初始化数组每个元素的初始值

返回值

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

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

异常

可能抛出由 Alloc :: allocate ( ) T 的构造函数所抛出的异常。若抛出异常,则 (1) 不产生任何效果。 若在数组构造过程中抛出异常,则以逆序销毁已初始化的元素 (C++20 起)

注释

这些函数通常会分配比 sizeof ( T ) 更多的内存,以便为内部簿记结构(如引用计数)预留空间。

std::make_shared 类似,此函数通常仅执行一次内存分配,并将 T 对象与控制块共同置于分配的内存块中(标准建议但不强制要求此行为,目前所有已知实现均采用此方式)。存储 alloc 的副本作为控制块的一部分,以便在共享引用计数和弱引用计数均归零时用于释放内存。

std::shared_ptr constructors 不同, 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_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();
} //< 所有 shared_ptr 在超出作用域时将自动清理

输出:

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
(公开成员函数)
创建管理新对象的共享指针
(函数模板)