Namespaces
Variants

std::shared_ptr<T>:: shared_ptr

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)
constexpr shared_ptr ( ) noexcept ;
(1)
constexpr shared_ptr ( std:: nullptr_t ) noexcept ;
(2)
template < class Y >
explicit shared_ptr ( Y * ptr ) ;
(3)
template < class Y, class Deleter >
shared_ptr ( Y * ptr, Deleter d ) ;
(4)
template < class Deleter >
shared_ptr ( std:: nullptr_t ptr, Deleter d ) ;
(5)
template < class Y, class Deleter, class Alloc >
shared_ptr ( Y * ptr, Deleter d, Alloc alloc ) ;
(6)
template < class Deleter, class Alloc >
shared_ptr ( std:: nullptr_t ptr, Deleter d, Alloc alloc ) ;
(7)
template < class Y >
shared_ptr ( const shared_ptr < Y > & r, element_type * ptr ) noexcept ;
(8)
template < class Y >
shared_ptr ( shared_ptr < Y > && r, element_type * ptr ) noexcept ;
(8) (自 C++20 起)
shared_ptr ( const shared_ptr & r ) noexcept ;
(9)
template < class Y >
shared_ptr ( const shared_ptr < Y > & r ) noexcept ;
(9)
shared_ptr ( shared_ptr && r ) noexcept ;
(10)
template < class Y >
shared_ptr ( shared_ptr < Y > && r ) noexcept ;
(10)
template < class Y >
explicit shared_ptr ( const std:: weak_ptr < Y > & r ) ;
(11)
template < class Y >
shared_ptr ( std:: auto_ptr < Y > && r ) ;
(12) (在 C++17 中移除)
template < class Y, class Deleter >
shared_ptr ( std:: unique_ptr < Y, Deleter > && r ) ;
(13)

从多种指针类型构造新的 shared_ptr ,这些指针指向需要管理的对象。

为便于下文描述,当满足以下任一条件时,称指针类型 Y* 指针类型 T* 兼容: Y* 可转换为 T* ,或 Y 是数组类型 U[N] T U cv [] (其中 cv 为某些 cv 限定符组合)。

(since C++17)
1,2) 构造一个没有托管对象的 shared_ptr ,即空 shared_ptr
3-7) 构造一个以 ptr 作为被管理对象指针的 shared_ptr

对于 (3,4,6) Y* 必须可转换为 T*

(C++17 前)

T 是数组类型 U[N] ,当 Y(*)[N] 是无效类型或不可转换为 T* 时, (3,4,6) 不参与重载决议。若 T 是数组类型 U[] ,当 Y(*)[] 是无效类型或不可转换为 T* 时, (3,4,6) 不参与重载决议。否则,当 Y* 不可转换为 T* 时, (3,4,6) 不参与重载决议。

(C++17 起)
此外:
3) 使用 delete 表达式 delete ptr (若 T 不是数组类型); delete [ ] ptr (若 T 是数组类型) (C++17 起) 作为删除器。 Y 必须是完整类型。该 delete 表达式必须格式正确、具有明确定义的行为且不抛出任何异常。 此构造函数额外不参与重载决议,若 delete 表达式格式不正确。 (C++17 起)
4,5) 使用指定的删除器 d 作为删除器。表达式 d ( ptr ) 必须格式正确、具有明确行为且不抛出任何异常。 d 的构造以及从其复制的存储删除器的构造不得抛出异常。

Deleter 必须满足 可复制构造 (CopyConstructible)

(C++17 前)

如果表达式 d ( ptr ) 格式不正确,或如果 std:: is_move_constructible_v < D > false ,则这些构造函数额外不参与重载决议。

(C++17 起)
6,7) (4,5) 相同,但额外使用 alloc 的副本用于内部数据分配。 Alloc 必须满足 分配器 要求。
8) 别名构造函数 :构造一个与 r 初始值共享所有权信息,但持有无关且非托管的指针 ptr shared_ptr 。若此 shared_ptr 是组中最后一个离开作用域的,它将调用最初由 r 管理的对象所存储的删除器。然而,对此 shared_ptr 调用 get() 将始终返回 ptr 的副本。程序员需确保在此 shared_ptr 存续期间 ptr 保持有效,例如在典型使用场景中: ptr 是由 r 管理的对象的成员,或是 r.get() 的别名(如下行转换) 对于接受右值的第二个重载,调用后 r 为空且 r. get ( ) == nullptr (C++20 起)
9) 构造一个与 r 所管理对象共享所有权的 shared_ptr 。若 r 未管理任何对象,则 * this 亦不管理任何对象。当 Y* 不能 隐式转换为 (C++17 前) 兼容 (C++17 起) T* 时,该模板重载不参与重载决议。
10) r 移动构造一个 shared_ptr 。构造完成后, * this 包含 r 先前状态的副本, r 变为空且其存储的指针为 null。若 Y* 不能 隐式转换为 (C++17 前) (C++17 起) T* 兼容,则该模板重载不参与重载决议。
11) 构造一个与 r 管理的对象共享所有权的 shared_ptr Y* 必须可隐式转换为 T* (C++17 前) 此重载仅在 Y* T* 兼容时参与重载决议。 (C++17 起) 注意 r. lock ( ) 可用于相同目的:区别在于当参数为空时,该构造函数会抛出异常,而 std:: weak_ptr < T > :: lock ( ) 在这种情况下会构造一个空的 std::shared_ptr
12) 构造一个存储并拥有原本由 r 所拥有对象的 shared_ptr Y* 必须可转换为 T* 。构造完成后, r 变为空。
13) 构造一个管理 r 当前所管理对象的 shared_ptr 。与 r 关联的删除器将被存储用于未来删除被管理对象。调用后 r 不再管理任何对象。
如果 std::unique_ptr<Y, Deleter>::pointer T* 不兼容,此重载不参与重载决议。 如果 r. get ( ) 是空指针,此重载等价于默认构造函数 (1) (C++17 起)
如果 Deleter 是引用类型,则等价于 shared_ptr ( r. release ( ) , std:: ref ( r. get_deleter ( ) ) 。否则等价于 shared_ptr ( r. release ( ) , std :: move ( r. get_deleter ( ) ) )

T 不是数组类型时,重载 (3,4,6) 允许通过 ptr 使用 shared_from_this ,而重载 (13) 允许通过 r. release ( ) 返回的指针使用 shared_from_this

目录

参数

ptr - 指向要管理的对象的指针
d - 用于销毁对象的删除器
alloc - 用于内部数据分配的内存分配器
r - 用于共享所有权或获取所有权的另一个智能指针

后置条件

1,2) use_count() 等于 0 get() 等于 nullptr
3-7) use_count() 等于 1 get() 等于 ptr
8) get() 等于 ptr 。对于第二个重载, r 为空且 r. get ( ) 等于 nullptr
9) get() 等于 r. get ( ) use_count() 等于 r. use_count ( )
10) r 应为空且 r. get ( ) 应等于 nullptr ,同时 * this 应为 r 的旧值。
11) use_count() 等于 r. use_count ( )
12) use_count() 等于 1 r. get ( ) 等于 nullptr

异常

3) std::bad_alloc 如果无法获取所需的额外内存。对于其他错误可能抛出实现定义的异常。若发生异常,当 T 不是数组类型时调用 delete ptr ,否则调用 delete [ ] ptr (C++17 起)
4-7) std::bad_alloc 若无法获取所需的额外内存。对于其他错误可能抛出实现定义的异常。若发生异常,将调用 d ( ptr )
11) std::bad_weak_ptr r. expired ( ) == true 。此种情况下构造函数无实际效果。
12) std::bad_alloc 若无法获取所需的额外内存。对于其他错误可能抛出实现定义的异常。若发生异常,此构造函数无任何效果。
13) 如果抛出异常,构造函数将不产生任何效果。

注释

构造函数通过类型为 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 起成为必需。

原始指针的重载版本会接管所指对象的所有权。因此,若对已被 shared_ptr 管理的对象使用原始指针重载构造 shared_ptr (例如通过 shared_ptr ( ptr. get ( ) ) ),即使该对象继承自 std::enable_shared_from_this ,仍可能导致未定义行为。

由于默认构造函数是 constexpr 的,静态 shared_ptr 会作为 静态非局部初始化 的一部分,在任何动态非局部初始化开始之前完成初始化。这使得在任何静态对象的构造函数中使用 shared_ptr 都是安全的。

在 C++11 和 C++14 中,可以从 std:: unique_ptr < T [ ] > 构造 std:: shared_ptr < T >

std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));
(注:根据要求,代码块内的所有C++代码和HTML标签均保持原样未翻译)

由于 shared_ptr 从其 std::unique_ptr 获取删除器(一个 std:: default_delete < T [ ] > 对象),该数组将被正确释放。

这在 C++17 中不再被允许。应改用数组形式 std:: shared_ptr < T [ ] >

示例

#include <iostream>
#include <memory>
struct Foo
{
    int id{0};
    Foo(int i = 0) : id{i} { std::cout << "Foo::Foo(" << i <<  ")\n"; }
    ~Foo() { std::cout << "Foo::~Foo(), id=" << id << '\n'; }
};
struct D
{
    void operator()(Foo* p) const
    {
        std::cout << "Call delete from function object. Foo::id=" << p->id << '\n';
        delete p;
    }
};
int main()
{
    {
        std::cout << "1) constructor with no managed object\n";
        std::shared_ptr<Foo> sh1;
    }
    {
        std::cout << "2) constructor with object\n";
        std::shared_ptr<Foo> sh2(new Foo{10});
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::shared_ptr<Foo> sh3(sh2);
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::cout << "sh3.use_count(): " << sh3.use_count() << '\n';
    }
    {
        std::cout << "3) constructor with object and deleter\n";
        std::shared_ptr<Foo> sh4(new Foo{11}, D());
        std::shared_ptr<Foo> sh5(new Foo{12}, [](auto p)
        {
            std::cout << "Call delete from lambda... p->id=" << p->id << '\n';
            delete p;
        });
    }
}

输出:

1) constructor with no managed object
2) constructor with object
Foo::Foo(10)
sh2.use_count(): 1
sh2.use_count(): 2
sh3.use_count(): 2
Foo::~Foo(), id=10
3) constructor with object and deleter
Foo::Foo(11)
Foo::Foo(12)
Call delete from lambda... p->id=12
Foo::~Foo(), id=12
Call delete from function object. Foo::id=11
Foo::~Foo(), id=11

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

缺陷报告 应用于 发布时的行为 正确行为
LWG 3548 C++11 来自 unique_ptr 的构造函数对删除器进行了复制构造 改为移动构造

参见

创建管理新对象的共享指针
(函数模板)
创建使用分配器分配新对象的共享指针
(函数模板)
允许对象创建指向自身的 shared_ptr
(类模板)