在上一篇文章中介绍了 shared_ptr 这种智能指针,他为了解决在指针没有引用的情况下自动回收资源这种情况而产生的,但是在部分情况下会产生另一种问题,那就是两个智能指针被循环引用 , a 使用 shared_ptr 引用了b ,同时 b 使用 shared_ptr 引用了 a,在 方法执行完成后 ,a 与 b 的智能指针都会被 释放,但是 由于他们互相持有 , a 与 b 的 used_count >0 ,那么就不会释放他们的资源,看下面的例子
c
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class Person{
public:
// 构造方法 ,name 是必要参数 mum 与 dad 是非必要参数
Person(string name,shared_ptr<Person> mum = nullptr ,shared_ptr<Person> dad = nullptr)
:name(name) ,mum(mum),dad(dad)// 此种初始化方式被经常应用到 jni 源码上
{
}
// 析构函数,资源被释放时会被调用
~Person(){
cout<<"对象名称是->" << name<< "被回收了"<<endl;
}
// 向量
vector<shared_ptr<Person>> child;
//名字
string name;
// 智能指针引用mum
shared_ptr<Person> mum;
//智能指针引用dad
shared_ptr<Person> dad;
};
// 初始化 家人,让他们循环引用
shared_ptr<Person> getFamily(const string& name){
shared_ptr<Person> mum(new Person(name +"'s Mum"));
shared_ptr<Person> dad(new Person(name +"'s Dad"));
shared_ptr<Person> child(new Person(name,mum,dad));
mum->child.push_back(child);
dad->child.push_back(child);
return child;
}
int main(){
shared_ptr<Person> tsm= getFamily("tsm");
cout<< "------------before change-----------"<<endl;
cout << tsm->dad->name<<endl;
cout << tsm->mum->name<<endl;
cout << tsm->name<<endl;
cout<<"tsm 的引用个数" <<tsm.use_count()<<endl;
cout<< "------------start change-----------"<<endl;
tsm = getFamily("tsm1");
cout<< "------------after change-----------"<<endl;
system("pause");
return 0;
}
结果:
lua
D:\CWorkSpace\tsmTest\cmake-build-debug\tsmTest.exe
------------before change-----------
tsm's Dad
tsm's Mum
tsm
tsm 的引用个数3
------------start change-----------
------------after change-----------
. . . pause . . .
发现在为 tsm 这个变量二次赋值时,第一次 shared_ptr 指针指向的资源内存应该是被释放的,但是他们的析构函数并没有被执行,那就证明他的资源并没有被释放,那么我们如何来修改内,这就引出了我们今天的主角 weak_ptr
修改如下
arduino
class Person{
public:
// 构造方法 ,name 是必要参数 mum 与 dad 是非必要参数
Person(string name,shared_ptr<Person> mum = nullptr ,shared_ptr<Person> dad = nullptr)
:name(name) ,mum(mum),dad(dad)// 此种初始化方式被经常应用到 jni 源码上
{
}
// 析构函数,资源被释放时会被调用
~Person(){
cout<<"对象名称是->" << name<< "被回收了"<<endl;
}
// 将向量中的引用使用 weak_ptr ,打破互相引用即可
vector<weak_ptr<Person>> child;
//名字
string name;
// 智能指针引用mum
shared_ptr<Person> mum;
//智能指针引用dad
shared_ptr<Person> dad;
};
修改后的结果如下:
rust
------------before change-----------
tsm's Dad
tsm's Mum
tsm
tsm 的引用个数1
------------start change-----------
对象名称是->tsm被回收了
对象名称是->tsm's Dad被回收了
对象名称是->tsm's Mum被回收了
------------after change-----------
发现在使用 weak_ptr 打破互相引用的后, 被覆盖的 tsm 的析构函数被成功调用了,
weak_ptr 的使用场景主要有2个
1: 打破 shared_ptr 使用混乱出现的情况导致循环引用的情况,
2: 如果持有该 shared_ptr 的对象的生命周期是大于 该 shared_ptr 指针的生命周期的情况,就会导致 shared_ptr 资源无法被回收,
weak_ptr 的创建方式有3中
1:
arduino
weak_ptr<Person> t0; 构造空对象
2:
arduino
weak_ptr<Person> t1(t0); 使用拷贝构造函数
3: 使用 shared_ptr 对象初始化
ini
shared_ptr<Person> tsm= getFamily("tsm");
weak_ptr<Person> t2(tsm);
检查weak_ptr 是否还有效
scss
t2.expired()
expired 源码如下
arduino
bool
expired() const noexcept
{ return _M_refcount._M_get_use_count() == 0; }
可以看到 返回的是 use_count ,那就证明 if(!t2.expired) 则证明他是有效的
使用 weak_ptr,使用lock 方法将 weak_ptr 转换成 shared_ptr ,防止在使用过程中资源被回收
ini
shared_ptr<Person> tt = t2.lock();
看一下lock 的源码
arduino
shared_ptr<_Tp>
lock() const noexcept
{ return shared_ptr<_Tp>(*this, std::nothrow); }