C++智能指针:weak_ptr
weak_ptr虽然是智能指针,但实际上是作为shared_ptr的辅助指针使用。
weak_ptr通常不单独使用,一般用于查看对应的shared_ptr的信息。weak_ptr没有重载*,->等指针运算符。
weak_ptr对象不会影响shared_ptr对象的引用计数。
#include<iostream> #include<string.h> #include<memory> #include<stdio.h> using namespace std; int main() { //创建空weak_ptr对象 weak_ptr<double> w1; /*注意:不能使用nullptr构造weak_ptr对象,这一点与shared_ptr,unique_ptr都不同!*/ weak_ptr<double> w1(nullptr); //错误 //使用拷贝构造函数初始化weak_ptr对象 weak_ptr<double> w2(w1); /* 使用shared_ptr对象初始化weak_ptr对象 注意:即使通过shared_ptr对象初始化weak_ptr对象,shared_ptr对象的引用计数也不会发生变化。 */ shared_ptr<double> s3(new int(6)); weak_ptr<double> w3(s3); weak_ptr<double> w4 = s3; //注意:不能使用堆指针初始化weak_ptr对象 weak_ptr<double> w5(new double); //错误 //weak_ptr类只重载了=赋值运算符,可以把一个shared_ptr或weak_ptr对象赋给另一个weak_ptr对象。 w4 = w3; return 0; }
使用weak_ptr解决shared_ptr循环引用问题
循环引用现象
shared_ptr的循环引用,是因为shared_ptr对象虽然被销毁,但其引用计数没有变为0,导致开辟的内存没有被释放:
#include<iostream> #include<string.h> #include<memory> #include<stdio.h> using namespace std; class A; class B; class A { public: shared_ptr<B> bb; //解决循环引用:用weak_ptr代替 public: A() { printf("A()\n"); } ~A() { printf("~A()\n"); } }; class B { public: shared_ptr<A> aa; //解决循环引用:用weak_ptr代替 public: B() { printf("B()\n"); } ~B() { printf("~B()\n"); } } int main() { shared_ptr<A> a(new A()); //a.use_count: 1 shared_ptr<B> b(new B()); //b.use_count: 1 a->bb = b; //b.use_count: 2 b->aa = a; //a.use_count: 2 return 0; } /*对象a,b生命周期结束时,b先销毁,b count=1,a再销毁,a count=1,于是a,b内部指针指向的内存没有被释放,造成内存泄漏*/
内存空间分析
细究一下上面代码的内存空间情况,首先通过shared_ptr a,b对象开辟了两个内存空间ma,mb以及对应的内部指针pa,pb,然后在pa指向的内存空间中通过b_存放了pb指针和空间mb,在pb指向的内存空间中通过a_存放了pa指针和空间ma,接着a,b对象分别被销毁,引用计数为1,因此指针pa,pb没有被销毁,内存空间ma,mb没有被释放。
可知,如果要解决循环引用的话,需要把其中一块内存空间手动释放,比如:
b->aa.reset();
或者,在智能指针赋值时只设置内部指针,不改变引用计数,也能解决循环引用。这就是weak_ptr的作用了。
weak_ptr解决循环引用
在类成员变量中使用weak_ptr,对象初始化时使用shared_ptr,就能够成功释放开辟的内存:
b->aa = a,a->bb=b没有影响引用计数,因此a,b销毁时,a,b内部指针指向的内存空间也被正常释放了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!