std::shared_ptr<T>::shared_ptr

来自cppreference.com
< cpp‎ | memory‎ | shared ptr
 
 
工具库
通用工具
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中弃用)
整数比较函数
(C++20)(C++20)(C++20)
(C++20)
swap 与类型运算
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
常用词汇类型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)

初等字符串转换
(C++17)
(C++17)
栈踪
 
动态内存管理
智能指针
(C++11)
(C++11)
(C++11)
(C++17 前)
(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++11)(C++23 前)
杂项
(C++20)
(C++11)
(C++11)
C 库
低层内存管理
 
 
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* ,或 YU[N] 类型数组而 TU cv [] (其中 cv 是某个 cv 限定符集合),则说 Y* 兼容 T*

(C++17 起)
1-2) 构造无被管理对象的 shared_ptr ,即空 shared_ptr
3-7) 构造 shared_ptr ,管理 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 的构造和从 d 构造存储的删除器必须不抛异常。

Deleter 必须可复制构造 (CopyConstructible)

(C++17 前)

若表达式 d(ptr) 非良构,或若 std::is_move_constructible<D>::valuefalse ,则这些构造函数不额外参与重载决议。

(C++17 起)
6-7)(4-5) ,但额外地用 alloc 的副本分配内部使用的数据。 Alloc 必须是分配器 (Allocator)
8) 别名使用构造函数:构造 shared_ptr ,与 r 的初始值共享所有权信息,但保有无关且不管理的指针 ptr 。若此 shared_ptr 是离开作用域的组中的最后者,则它将调用最初 r 所管理对象的析构函数。然而,在此 shared_ptr 上调用 get() 将始终返回 ptr 的副本。程序员负责确保只要此 shared_ptr 存在,此 ptr 就保持合法,例如在典型使用情况中,其中 ptrr 所管理对象的成员,或是 r.get() 的别名(例如向下转型)。对于接收右值的第二重载,调用后 r 为空且 r.get() == nullptr (C++20 起)
9) 构造 shared_ptr ,共享 r 所管理对象的所有权。若 r 不管理对象,则 *this 亦不管理对象。若 Y*可隐式转换为 (C++17 前)兼容 (C++17 起) T* ,则模板重载不参与重载决议。
10)r 移动构造 shared_ptr 。构造后, *thisr 先前状态的副本,而 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>::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

注解

T 不是数组类型是,重载 (3)(4)(6)ptr 启用 shared_from_this ,而重载 (13)r.release() 所返回的指针启用 shared_from_this 。

构造函数以 U* 类型指针 ptr 启用 shared_from_this ,表示它确定 U 是否拥有作为 std::enable_shared_from_this 特化的无歧义且可访问 (C++17 起)基类,而若如此,则构造函数求值该语句:

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_thisstd::shared_from_this 的隐藏 mutable std::weak_ptr 成员。对 weak_this 成员的赋值不是原子的,且与任何到同一对象的潜在并发访问冲突。这确保将来对 shared_from_this() 调用,将与此裸指针构造函数所创建的 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_ptrs 作为静态非局部初始化的一部分初始化,在任何动态初始化开始前。这使得在任何静态对象的构造函数中使用 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_ptrunique_ptr 获得其删除器( std::default_delete<T[]> 对象),故能正确解分配数组。

C++17 中这不再受允许。应当使用替代的数组形式 std::shared_ptr<T[]>

参数

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) 若抛异常,则构造函数无效果。

示例

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

输出:

constructor with no managed object
constructor with object
Foo...
2
2
~Foo...
constructor with object and deleter
Foo...
Foo...
Call delete from lambda...
~Foo...
Call delete from function object...
~Foo..

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR 应用于 出版时的行为 正确行为
LWG 3548 C++11 源自 unique_ptr 的构造函数复制构造删除器 改为移动构造

参阅

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