命名空间
变体
操作

std::shared_ptr<T>::shared_ptr

来自 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*)
显式生命周期管理
 
 
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 是数组类型 U[N]TU cv [](其中 cv 是一些 cv-限定符集),则指针类型 Y* 被认为是与指针类型 T* 兼容的

(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-expression delete ptr 如果 T 不是数组类型;如果 T 是数组类型,则为 delete[] ptr(C++17 起) 作为删除器。Y 必须是一个完整类型。删除表达式必须格式良好,行为明确,且不抛出任何异常。如果删除表达式格式不良好,则此构造函数不参与重载决议。(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 必须是 Allocator
8) 别名构造函数:构造一个 shared_ptr,它与 r 的初始值共享所有权信息,但持有一个不相关且未管理的指针 ptr。如果这个 shared_ptr 是最后一组超出范围的,它将为最初由 r 管理的对象调用存储的删除器。然而,在这个 shared_ptr 上调用 get() 总是返回 ptr 的副本。程序员有责任确保只要此 shared_ptr 存在,此 ptr 就保持有效,例如在典型用例中,ptr 是由 r 管理的对象的成员或 r.get() 的别名(例如,向下转型)。对于接受右值的第二个重载,调用后 r 为空且 r.get() == nullptr(C++20 起)
9) 构造一个 shared_ptr,它与 r 管理的对象共享所有权。如果 r 不管理任何对象,则 *this 也不管理任何对象。如果 Y*隐式转换为(C++17 前)兼容(C++17 起) T*,则模板重载不参与重载决议。
10)r 移动构造一个 shared_ptr。构造后,*this 包含 r 之前状态的副本,r 为空,其存储的指针为空。如果 Y*隐式转换为(C++17 前)兼容(C++17 起) T*,则模板重载不参与重载决议。
11) 构造一个 shared_ptr,它与 r 管理的对象共享所有权。Y* 必须隐式转换为 T*(C++17 前)此重载仅在 Y*T* 兼容时参与重载决议。(C++17 起) 请注意,r.lock() 可用于相同目的:区别在于如果参数为空,此构造函数会抛出异常,而 std::weak_ptr<T>::lock() 在这种情况下会构造一个空的 std::shared_ptr
12) 构造一个 shared_ptr,它存储并拥有以前由 r 拥有的对象。Y* 必须可以转换为 T*。构造后,r 为空。
13) 构造一个 shared_ptr,它管理当前由 r 管理的对象。与 r 关联的删除器存储起来,以便将来删除管理的对象。调用后,r 不管理任何对象。
如果 std::unique_ptr<Y, Deleter>::pointerT*兼容,则此重载不参与重载决议。如果 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 - 另一个智能指针,用于共享所有权或从中获取所有权

[编辑] 异常

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

[编辑] 注意

构造函数启用 shared_from_this,带一个类型为 U* 的指针 ptr,这意味着它确定 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(ptr.get()))使用原始指针重载构造 shared_ptr 可能会导致未定义行为,即使对象类型派生自 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));

由于 shared_ptrstd::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
(类模板) [编辑]
English 日本語 中文(简体) 中文(繁體)