当前位置: 首页 > news >正文

智能指针中的weak_ptr(弱引用智能指针)

弱引用智能指针 std::weak_ptr 可以看做是shared_ptr的助手,它不管理 shared_ptr 内部的指针。std::weak_ptr 没有重载操作符*和->,因为它不共享指针,

不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的主要作用就是作为一个旁观者监视shared_ptr 中管理的资源是否存在.

初始化

#include<iostream>
#include<memory>
using namespace std;int main(){shared_ptr<int> sp(new int);//weak_ptr<int> wp1;//空weak_ptr对象weak_ptr<int> wp2(wp1);//也是空weak_ptr<int> wp3(sp);//通过shared_ptr对象构造一个可用的weak_ptr实例对象,就是wp3监管spweak_ptr<int> wp4;wp4=sp;//通过shared_ptr对象构造一个可用的weak_ptr实例对象(这是一个隐式类型转换),给赋值运算符重载了weak_ptr<int> wp5;wp5=wp3;//通过weak_ptr对象构造一个可用的weak_ptr实例对象,给赋值运算符重载了
}
use_count()

通过调用weak_ptr类提供的use_count()方法可以获得当前观测资源的引用计数

#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> sp(new int);
weak_ptr<int> wp1;
weak_ptr<int> wp2(wp1);
weak_ptr<int> wp3(sp);
weak_ptr<int> wp4;
wp4 = sp;
weak_ptr<int> wp5;
wp5 = wp3;
cout << wp1.use_count() << endl;
cout << wp2.use_count() << endl;
cout << wp3.use_count() << endl;
cout << wp4.use_count() << endl;
cout << wp5.use_count() << endl;
}/*运行结果:
0
0
1
1
1*/

通过打印的结果可以知道,虽然弱引用智能指针 wp3、wp4、wp5 监测的资源是同一个,但是它的引用计数并没有发生任何的变化,也进一步证明了 weak_ptr 只是监测资源,并不管理资源。

expired()(失效的)

通过调用 std::weak_ptr 类提供的 expired()方法来判断观测的资源是否已经被释放

#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> shared(new int(10));
weak_ptr<int> weak(shared);
cout << weak.expired() << endl;
shared.reset();
cout << weak.expired() << endl;return 0;
}
/*运行结果:
0
1*/

weak_ptr监测的就是shared_ptr管理的资源,当共享智能指针调用 shared.reset();之后管理的资源被释放,因此 weak.expired()函数的结果返回 true,表示监测的资源已经不存在了。

lock()

通过调用weak_ptr类提供的lock()方法来获取管理所监测资源的shared_ptr对象

#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> sp1, sp2;
weak_ptr<int> wp;
sp1 = make_shared<int>(520);
wp = sp1;
sp2 = wp.lock();
cout << wp.use_count() << endl;
sp1.reset();
cout << wp.use_count() << endl;
sp1 = wp.lock();
cout << wp.use_count() << endl;cout << *sp1 << endl;
cout << *sp2 << endl;return 0;
}/*运行结果:
2
1
2
520
520*/

sp2 = wp.lock();通过调用 lock()方法得到一个用于管理 weak_ptr 对象所监测的资源的共享智能指针对象,使用这个对象初始化 sp2,此时所监测资源的引用计数为 2.

sp1.reset();共亨智能指针 sp1 被重置,weak_ptr 对象所监测的资源的引用计数减 1

sp1 = wp.lock();sp1 重新被初始化,并且管理的还是 weak_ptr 对象所监测的资源,因此引用计数加 1.

共享智能指针对象 sp1 和 sp2 管理的是同一块内存,因此最终打印的内存中的结果是相同的,都是 520.

reset()

通过调用 std::weak_ptr 类提供的 reset()方法来清空对象,使其不监测任何资源。

#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> sp(new int(10));
weak_ptr<int> wp(sp);
cout << wp.expired() << endl;
wp.reset();
cout << wp.expired() << endl;
cout << sp.use_count() << endl;return 0;
}/*运行结果:
0
1
1*/
返回管理this的shared_ptr
#include<iostream>
#include<memory>
using namespace std;struct Test
{shared_ptr<Test> getSharedPtr(){return shared_ptr<Test>(this);  }~Test(){cout<<"析构函数"<<endl;    }
};
int main()
{shared_ptr<Test> sp1(new Test);cout<<"引用个数"<<sp1.use_count()<<endl;shared_ptr<Test> sp2=sp1->getSharedPtr();cout<<"引用个数"<<sp1.use_count()<<endl;return 0;
}

当用Test的对象初始化sp1时,sp1指向这个对象,当sp1调用getSharedPtr函数时,要给隐含参数this传值,传的就是Test对象的原始地址,这就会导致用原始地址初始化多次智能指针,这俩智能指针各自维护着自己的引用计数,当一个引用计数为0时,就会释放那块空间,而另一个指针不知道那块空间被释放,会再次释放那块空间,导致二次释放问题

通过输出的结果可以看到一个对象被析构了两次,其原因是这样的:在这个例子中使用同一个指针 this 构造了两个智能指针对象 sp1 和 sp2,这二者之间是没有任何关系的,因为 sp2 并不是通过 sp1 初始化得到的实例对象。在离开作用域之后 this 将被构造的两个智能指针各自析构导致重复析构的错误。

循环引用
#include<iostream>
#include<memory>
using namespace std;class A;
class B;
class A{
public:shared_ptr<B> bptr;~A(){cout<<"A的析构"<<endl;    }    
};
class B{
public:shared_ptr<A> aptr;~B(){cout<<"B的析构"<<endl;    }    
};
void testPtr(){shared_ptr<A> ap(new A);shared_ptr<B> bp(new B);cout<<"A的引用计数:"<<ap.use_count()<<endl;cout<<"B的引用计数:"<<bp.use_count()<<endl;ap->bptr=bp;bp->aptr=ap;cout<<"A的引用计数:"<<ap.use_count()<<endl;cout<<"B的引用计数:"<<bp.use_count()<<endl;
}
int main(){testPtr();return 0;    
}

当作用域结束,想要释放A对象,就得让A对象里面的bptr引用计数为0,但是aptr指向的是B,只有B没有,bptr引用计数才为0,但是B里有个aptr,只有aptr引用计数为0,B才能没,但是aptr指向的是A,只有A没了,aptr才能没,这就导致,两边都没不了,ap和bp引用计数都不为0

要解决这个循环引用问题,可以考虑使用weak_ptr(弱指针)来打破循环引用,例如将类A中的shared_ptr改为weak_ptr,类B中的shared_ptr改为weak_ptr,这样就可以在需要访问对方对象时通过weak_ptr的lock方法来获取有效的shared_ptr,同时又不会造成循环引用导致的析构函数无法调用的问题。

http://www.lryc.cn/news/501243.html

相关文章:

  • 【电子通识】机电继电器和固态继电器的区别
  • 工业异常检测-CVPR2024-新的3D异常数据合成办法和自监督网络IMRNet
  • 如何创建对话窗口
  • 新手上路,学Go还是Python
  • <!DOCTYPE html>的作用是什么
  • EasyExcel改名为FastExce做了那些改变呢
  • 狗狗的生育周期:关注与呵护
  • ABAP DIALOG屏幕编程2
  • 获取缓存大小与清除 Web 缓存 - 鸿蒙 HarmonyOS Next
  • 在Unreal Engine中,UHT与反射机制
  • SQL项目实战与综合应用——项目设计与需求分析
  • 分布式中的CAP定理和BASE理论与强弱一致性
  • C/C++常见符号与运算符
  • 了解 k8s 网络基础知识
  • 用户信息界面按钮禁用+发送消息功能
  • 接近开关传感器-PCB线图电感式传感器【衰减系数1】
  • C/C++流星雨
  • 计算机网络:传输层、应用层、网络安全、视频/音频/无线网络、下一代因特网
  • [漏洞挖掘与防护] 05.CVE-2018-12613:phpMyAdmin 4.8.1后台文件包含缺陷复现及防御措施
  • GroundingDINO微调训练_训练日志解释
  • 【0362】Postgres内核 XLogReaderState readBuf 有完整 XLOG page header 信息 ? ( 7 )
  • H5接入Steam 获取用户数据案例 使用 OpenID 登录绑定公司APP账户 steam公开用户信息获取 steam webapi文档使用
  • pytorch多GPU训练教程
  • 力扣--LCR 178.训练计划VI
  • Linux 网络接口配置
  • 【从零开始入门unity游戏开发之——C#篇01】理论开篇
  • ABAP开发-批量导入BAPI和BDC_1
  • RabbitMQ七种工作模式之 RPC通信模式, 发布确认模式
  • 并非传统意义上的整体二分
  • PostgreSQL的一主一从集群搭建部署 (同步)