命名空间
变体
操作

std::shared_ptr

来自 cppreference.com
< cpp‎ | memory
 
 
实用程序库
语言支持
类型支持 (基本类型,RTTI)
库特性测试宏 (C++20)
动态内存管理
程序实用程序
协程支持 (C++20)
可变参数函数
调试支持
(C++26)
三路比较
(C++20)
(C++20)(C++20)(C++20)
(C++20)(C++20)(C++20)
通用实用程序
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中已弃用)
整数比较函数
(C++20)(C++20)(C++20)   
(C++20)
交换类型操作
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
通用词汇类型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
基本字符串转换
(C++17)
(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)



 
 
定义在头文件 <memory>
template< class T > class shared_ptr;
(自 C++11 起)

std::shared_ptr 是一种智能指针,通过指针保留对对象的共享所有权。多个 shared_ptr 对象可以拥有同一个对象。当以下任一情况发生时,对象将被销毁,其内存将被释放

  • 拥有该对象的最后一个剩余的 shared_ptr 被销毁;
  • 拥有该对象的最后一个剩余的 shared_ptr 通过 operator=reset() 被分配了另一个指针。

该对象使用 delete 表达式 或在构造期间提供给 shared_ptr 的自定义删除器来销毁。

shared_ptr 可以共享对一个对象的拥有权,同时存储指向另一个对象的指针。此特性可用于指向成员对象,同时拥有它们所属的对象。存储的指针是通过 get()、解引用运算符和比较运算符访问的指针。当使用计数达到零时,传递给删除器的指针是托管指针。

shared_ptr 也可以不拥有任何对象,在这种情况下,它被称为(如果使用别名构造函数创建了一个空 shared_ptr,它可能具有一个非空存储指针)。

shared_ptr 的所有特化都满足 CopyConstructibleCopyAssignableLessThanComparable 的要求,并且可以 隐式转换为 bool

所有成员函数(包括复制构造函数和复制赋值运算符)都可以被多个线程在不同的shared_ptr对象上调用,而无需额外的同步,即使这些对象是副本并共享同一个对象的拥有权。如果多个执行线程在没有同步的情况下访问同一个shared_ptr对象,并且任何访问都使用了shared_ptr的非const成员函数,那么就会发生数据竞争;可以使用std::atomic<shared_ptr>来防止数据竞争。

目录

[edit] 成员类型

成员类型 定义
element_type
T (直到 C++17)
std::remove_extent_t<T> (自 C++17 起)
weak_type (自 C++17 起) std::weak_ptr<T>

[edit] 成员函数

构造新的shared_ptr
(公共成员函数) [edit]
如果不再有shared_ptr链接到它,则析构被拥有的对象
(公共成员函数) [edit]
赋值shared_ptr
(公共成员函数) [edit]
修改器
替换被管理的对象
(公共成员函数) [edit]
交换被管理的对象
(公共成员函数) [edit]
观察者
返回存储的指针
(公共成员函数) [edit]
解除对存储的指针的引用
(公共成员函数) [edit]
提供对存储的数组的索引访问
(公共成员函数) [edit]
返回引用同一个被管理对象的shared_ptr对象的数目
(公共成员函数) [edit]
(直到 C++20)
检查被管理的对象是否只由当前shared_ptr对象管理
(公共成员函数) [edit]
检查存储的指针是否不为空
(公共成员函数) [edit]
提供基于所有权的共享指针排序
(公共成员函数) [edit]
提供基于所有权的共享指针哈希
(公共成员函数) [edit]
提供基于所有权的共享指针相等比较
(公共成员函数) [edit]

[edit] 非成员函数

创建一个管理新对象的共享指针
(函数模板) [edit]
创建一个管理使用分配器分配的新对象的共享指针
(函数模板) [edit]
static_castdynamic_castconst_castreinterpret_cast应用于存储的指针
(函数模板) [edit]
如果拥有,则返回指定类型的删除器
(函数模板) [edit]
(在 C++20 中移除)(在 C++20 中移除)(在 C++20 中移除)(在 C++20 中移除)(在 C++20 中移除)(C++20)
与另一个shared_ptrnullptr比较
(函数模板) [edit]
将存储的指针的值输出到输出流
(函数模板) [edit]
专门化std::swap算法
(函数模板) [edit]
专门化std::shared_ptr的原子操作
(函数模板) [edit]

[edit] 辅助类

原子共享指针
(类模板专门化) [edit]
std::shared_ptr的哈希支持
(类模板专门化) [edit]

[edit] 推导指南 (自 C++17 起)

[edit] 备注

对象的拥有权只能通过将它的值复制构造或复制赋值到另一个shared_ptr来与另一个shared_ptr共享。使用另一个shared_ptr拥有的原始底层指针构造一个新的shared_ptr会导致未定义的行为。

std::shared_ptr可以与不完整类型T一起使用。但是,从原始指针构造的构造函数(template<class Y> shared_ptr(Y*))以及template<class Y> void reset(Y*)成员函数只能用指向完整类型的指针调用(注意,std::unique_ptr可以从指向不完整类型的原始指针构造)。

std::shared_ptr<T> 中,T 可以是函数类型:在这种情况下,它管理的是指向函数的指针,而不是指向对象的指针。这有时用于使动态库或插件在它的任何函数被引用时保持加载。

void del(void(*)()) {}
 
void fun() {}
 
int main()
{
    std::shared_ptr<void()> ee(fun, del);
    (*ee)();
}

[编辑] 实现说明

在典型实现中,shared_ptr 仅包含两个指针。

  • 存储的指针(由 get() 返回);
  • 指向控制块的指针。

控制块是动态分配的对象,它包含

  • 指向受管对象的指针或受管对象本身;
  • 删除器(类型擦除);
  • 分配器(类型擦除);
  • 拥有受管对象的 shared_ptr 数量;
  • 引用受管对象的 weak_ptr 数量。

当通过调用 std::make_sharedstd::allocate_shared 创建 shared_ptr 时,控制块和受管对象的内存通过一次分配创建。受管对象在控制块的数据成员中就地构造。当通过 shared_ptr 构造函数之一创建 shared_ptr 时,受管对象和控制块必须分别分配。在这种情况下,控制块存储指向受管对象的指针。

shared_ptr 直接持有的指针是由 get() 返回的指针,而控制块持有的指针/对象是在共享所有者数量达到零时将被删除的指针/对象。这些指针不一定相等。

shared_ptr 的析构函数递减控制块的共享所有者数量。如果该计数器达到零,控制块将调用受管对象的析构函数。在 std::weak_ptr 计数器也达到零之前,控制块不会自释放。

在现有的实现中,如果存在指向相同控制块的共享指针,则弱指针的数量将递增 ([1][2])。

为了满足线程安全要求,引用计数器通常使用相当于 std::atomic::fetch_add 的方法递增,并使用 std::memory_order_relaxed(递减需要更强的排序才能安全地销毁控制块)。

[编辑] 示例

#include <chrono>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
 
using namespace std::chrono_literals;
 
struct Base
{
    Base() { std::cout << "Base::Base()\n"; }
 
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "Base::~Base()\n"; }
};
 
struct Derived : public Base
{
    Derived() { std::cout << "Derived::Derived()\n"; }
 
    ~Derived() { std::cout << "Derived::~Derived()\n"; }
};
 
void print(auto rem, std::shared_ptr<Base> const& sp)
{
    std::cout << rem << "\n\tget() = " << sp.get()
              << ", use_count() = " << sp.use_count() << '\n';
}
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(987ms);
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
                                  // shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        print("Local pointer in a thread:", lp);
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 
    print("Created a shared Derived (as a pointer to Base)", p);
 
    std::thread t1{thr, p}, t2{thr, p}, t3{thr, p};
    p.reset(); // release ownership from main
 
    print("Shared ownership between 3 threads and released ownership from main:", p);
 
    t1.join();
    t2.join();
    t3.join();
 
    std::cout << "All threads completed, the last one deleted Derived.\n";
}

可能的输出

Base::Base()
Derived::Derived()
Created a shared Derived (as a pointer to Base)
	get() = 0x118ac30, use_count() = 1
Shared ownership between 3 threads and released ownership from main:
	get() = 0, use_count() = 0
Local pointer in a thread:
	get() = 0x118ac30, use_count() = 5
Local pointer in a thread:
	get() = 0x118ac30, use_count() = 4
Local pointer in a thread:
	get() = 0x118ac30, use_count() = 2
Derived::~Derived()
Base::~Base()
All threads completed, the last one deleted Derived.

[编辑] 示例

#include <iostream>
#include <memory>
 
struct MyObj
{
    MyObj() { std::cout << "MyObj constructed\n"; }
 
    ~MyObj() { std::cout << "MyObj destructed\n"; }
};
 
struct Container : std::enable_shared_from_this<Container> // note: public inheritance
{
    std::shared_ptr<MyObj> memberObj;
 
    void CreateMember() { memberObj = std::make_shared<MyObj>(); }
 
    std::shared_ptr<MyObj> GetAsMyObj()
    {
        // Use an alias shared ptr for member
        return std::shared_ptr<MyObj>(shared_from_this(), memberObj.get());
    }
};
 
#define COUT(str) std::cout << '\n' << str << '\n'
 
#define DEMO(...) std::cout << #__VA_ARGS__ << " = " << __VA_ARGS__ << '\n'
 
int main()
{
    COUT("Creating shared container");
    std::shared_ptr<Container> cont = std::make_shared<Container>();
    DEMO(cont.use_count());
    DEMO(cont->memberObj.use_count());
 
    COUT("Creating member");
    cont->CreateMember();
    DEMO(cont.use_count());
    DEMO(cont->memberObj.use_count());
 
    COUT("Creating another shared container");
    std::shared_ptr<Container> cont2 = cont;
    DEMO(cont.use_count());
    DEMO(cont->memberObj.use_count());
    DEMO(cont2.use_count());
    DEMO(cont2->memberObj.use_count());
 
    COUT("GetAsMyObj");
    std::shared_ptr<MyObj> myobj1 = cont->GetAsMyObj();
    DEMO(myobj1.use_count());
    DEMO(cont.use_count());
    DEMO(cont->memberObj.use_count());
    DEMO(cont2.use_count());
    DEMO(cont2->memberObj.use_count());
 
    COUT("Copying alias obj");
    std::shared_ptr<MyObj> myobj2 = myobj1;
    DEMO(myobj1.use_count());
    DEMO(myobj2.use_count());
    DEMO(cont.use_count());
    DEMO(cont->memberObj.use_count());
    DEMO(cont2.use_count());
    DEMO(cont2->memberObj.use_count());
 
    COUT("Resetting cont2");
    cont2.reset();
    DEMO(myobj1.use_count());
    DEMO(myobj2.use_count());
    DEMO(cont.use_count());
    DEMO(cont->memberObj.use_count());
 
    COUT("Resetting myobj2");
    myobj2.reset();
    DEMO(myobj1.use_count());
    DEMO(cont.use_count());
    DEMO(cont->memberObj.use_count());
 
    COUT("Resetting cont");
    cont.reset();
    DEMO(myobj1.use_count());
    DEMO(cont.use_count());
}

输出

Creating shared container
cont.use_count() = 1
cont->memberObj.use_count() = 0
 
Creating member
MyObj constructed
cont.use_count() = 1
cont->memberObj.use_count() = 1
 
Creating another shared container
cont.use_count() = 2
cont->memberObj.use_count() = 1
cont2.use_count() = 2
cont2->memberObj.use_count() = 1
 
GetAsMyObj
myobj1.use_count() = 3
cont.use_count() = 3
cont->memberObj.use_count() = 1
cont2.use_count() = 3
cont2->memberObj.use_count() = 1
 
Copying alias obj
myobj1.use_count() = 4
myobj2.use_count() = 4
cont.use_count() = 4
cont->memberObj.use_count() = 1
cont2.use_count() = 4
cont2->memberObj.use_count() = 1
 
Resetting cont2
myobj1.use_count() = 3
myobj2.use_count() = 3
cont.use_count() = 3
cont->memberObj.use_count() = 1
 
Resetting myobj2
myobj1.use_count() = 2
cont.use_count() = 2
cont->memberObj.use_count() = 1
 
Resetting cont
myobj1.use_count() = 1
cont.use_count() = 0
MyObj destructed

[编辑] 参见

具有唯一对象所有权语义的智能指针
(类模板) [编辑]
(C++11)
对由 std::shared_ptr 管理的对象的弱引用
(类模板) [编辑]