图文讲解 C++11 智能指针的实现

1、std::shared_ptr

1.1、总体关系

首先我们看看 shared_ptr 相关的类,主要是 __shared_ptr、__shared_count 和 _Sp_counted_base 这三个。

shared_ptr 继承 __shared_ptr,__shared_ptr 有两个成员变量:对象指针 _M_ptr 和引用计数 _M_refcount。

引用计数 __shared_count 主要借助 _Sp_counted_base 实现。

1.2、_Sp_counted_base<Lp>

_Sp_counted_base 是一个基类,有三个派生类,分别用于处理:

  • 传入裸指针
  • 指定 Deleter
  • 使用 make_shared
struct Foo {
  Foo(int val) : val(val) {}
  int val;
};

struct Deleter {
  void operator()(const Foo* p) const { delete p; }
};

std::shared_ptr<Foo> sp1(new Foo(1));
std::shared_ptr<Foo> sp2(new Foo(1), Deleter());
std::shared_ptr<Foo> sp3 = std::make_shared<Foo>(1);

使用 make_shared 方法,共享对象和引用计数在同一块内存。三种情况如下图所示:

<img src='./imgs/sp-counted-base.png'>

_M_dispose() 和 _M_destroy() 两个函数分别释放共享对象和引用计数的内存。由于 make_shared 方法共享对象和引用计数在同一块内存上,_M_despose() 函数只是调用共享对象的析构函数。

  • 当最有一个 shared_ptr 析构时,调用 _M_dispose() 函数释放共享对象内存
  • 当最后一个 weak_ptr 析构时,调用 _M_destroy() 函数释放引用计数内存

从上图可以看到,weak count = #weak + (#shared != 0),这么做的目的,是为了保证 shared_ptr 对象释放了,weak_ptr 对象还可以继续使用。

2、std::weak_ptr

不控制所指向对象生命周期的智能指针,它指向一个 shared_ptr 管理的对象,和 shared_ptr 共享引用计数对象。

weak_ptr 操作 _M_weak_count 计数,在最后一个 weak_ptr 析构时,释放引用计数内存。

3、enable_shared_from_this

enable_shared_from_this 字如其名,“只从 this 指针构造一个 shared_ptr 对象”。当然,并不是直接用 this 指针,而是在一个类的(成员函数)内部,构造该类的 shared_ptr 对象,并且和已有 shared_ptr 共享状态。

enable_shared_from_this 拥有一个 weak_ptr 成员 _M_weak_this,shared_from_this() 函数就是通过这个 weak_ptr 提升为 shared_ptr 返回给 user

比较有意思的是 _M_weak_this 的赋值,并不是在 enable_shared_from_this 构造函数中完成赋值的,而是在 __shared_ptr 构造函数中,调用 _M_enable_shared_from_this() 函数完成的。

_M_enable_shared_from_this() 函数使用模板,如果某个类是 enable_shared_from_this 的子类,就调用 _M_weak_assign() 函数。_M_weak_assign() 函数直接调用 weak_ptr::_M_assign() 函数完成对 weak_ptr 的赋值。

点击关注 “源知源为”,阅读更多技术干货
#智能指针##C++##C++11##应届生##shared_ptr#
C/C++基础 文章被收录于专栏

C/C++ 语言基础

全部评论
m
1 回复 分享
发布于 2023-08-07 09:48 重庆
好文,图很清晰
点赞 回复 分享
发布于 2023-08-05 09:39 江苏

相关推荐

2 21 评论
分享
牛客网
牛客企业服务