深入分析shared_ptr与weak_ptr的实现
stl中使用了shared_ptr来管理一个对象的内部指针,并且使用了weak_ptr来防止前面所提到的shared_ptr循环引用的问题。
接下来简单的分析shared_ptr和weak_ptr的实现,最后通过自己写代码来模拟shared_ptr和weak_ptr,达到深入学习的目的:
测试代码如下:
#include "stdafx.h"
#include <memory>
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<int> sptr(new int(3)); // 首先创建一个指针, 交给智能指针管理
// sptr, sptr2指向同一个内容, 引用计数为2
std::shared_ptr<int> sptr2 = sptr; // 同时赋值给另外一个智能指针
// 引入了第3个指针
std::weak_ptr<int> wptr = sptr;
// 弱指针如果想使用强指针, 必须先判断, 判断弱指针是否与强指针有一定的关联, 并且强指针是存在的
if (!wptr.expired()){
std::shared_ptr<int> sptr3 = wptr.lock(); // 使用的时候, 需要通过lock函数的提升, 变为强指针, 接下来就可以使用这个指针了
}
return 0;
}
代码运行分析:
出现了强指针和弱指针引用的次数
我们之前实现智能指针的时候, 也有引用计数, 当时只有1个数字, 而这里出现了2个数字
重新开程序, 单步走, 第1次只有1个强指针引用次数
继续单步走, sptr2 = sptr;
, 强引用次数变成了2
当我们, 把强指针赋值给了弱指针后, std::weak_ptr<int> wptr = sptr;
多了一个弱引用1, 表示有一个弱指针的存在, 在关联强指针
这时候, 想使用强指针的话, 先用弱指针判断有没有关联, if (!wptr.expired()){
如果和强指针有关联, 那么通过wptr.lock()
提升为强指针 std::shared_ptr<int> sptr3 = wptr.lock();
然后弱指针引用次数仍然为1, 强指针引用次数变为了3
需要有两个问题需要思考:
- 为什么会存在强弱指针的计数?
- 强弱指针计数的用途是什么? 具体的代码实现是什么 (其实和第1个问题重合, 如果知道了为什么存在, 也就知道了用途)
上节课循环引用的总结:
如何来避免这种情况
如果引用次数,两者都是2的话, 永远解决不了这个问题, 因为他们两个互相引用, 为了打破这个闭环, 这2者中有一个引用次数最好为1
但是减了1次, 统计的次数就会不准确, 讲道理本来是2次, 现在减为了1次, 不准确了啊
所以为了解决次数不准确的问题, C++不得不再引入一个新的概念, 叫弱指针
使用弱指针会存在一个问题, 弱指针和原来对象是关联的, 但是不能直接使用, 直接使用需要通过lock
函数来进行提升, 当使用的时候, 使用lock
函数提升一下, 就会增加相应的强引用次数, 这样做的话就可以打破闭环, 因为用了弱指针, 弱指针不影响原来的引用次数, 所以原来的引用次数为1
所以弱指针是这么来的, 把1个2减少为了1, 打破了闭环, 从而让他得以释放
弱指针和强指针有关联
为了管理强指针本身的对象, 我们引入强指针的引用次数
为了管理弱指针, 我们提供了weak_ptr_uses_count
, 通过弱指针的使用次数, 来管理弱指针对象
通过share_ptr_uses_ptr
来管理原来的指针
所以这里就分开了, 新增了弱指针的概念, 就不得不加一个weak_ptr_uses_count
将它关联起来
而share_ptr_uses_count
保持不变
通过这么样的一个处理, 解决了循环引用