网站搭建平台有哪些,中国勘察设计行业信息化建设网站,网站布局设计软件,工程建设管理网站源码目录
C智能指针之weak_ptr
概述
作用
本文涉及的所有程序
使用说明
weak_ptr的常规操作
lock();
use_count();
expired();
reset();
shared_ptr weak_ptr
尺寸
智能指针结构框架
常见使用问题
shared_ptr多次引用同一数据#xff0c;会导致两次释放同一内…目录
C智能指针之weak_ptr
概述
作用
本文涉及的所有程序
使用说明
weak_ptr的常规操作
lock();
use_count();
expired();
reset();
shared_ptr weak_ptr
尺寸
智能指针结构框架
常见使用问题
shared_ptr多次引用同一数据会导致两次释放同一内存只涉及shared_ptr
shared_ptr循环引用导致内存泄露涉及shared_ptr和weak_ptr
shared_ptr指向局部变量的地址会导致两次释放同一个内存只涉及shared_ptr
shared_ptr接收shared_ptr所实例化对象的this指针导致会导致两次释放同一个内存只涉及shared_ptr C智能指针之weak_ptr
概述
std::weak_ptr 是一种智能指针通常不单独使用只能和 shared_ptr 类型指针搭配使用可以视为 shared_ptr 指针的一种辅助工具。借助 weak_ptr 类型指针可以获取 shared_ptr 指针的一些状态信息比如有多少指向相同空间的 shared_ptr 指针、通过expired()判断shared_ptr 指针指向的堆内存是否已经被释放等等还可以解决shared_ptr 循环引用的问题。
weak_ptr类模板弱指针弱引用计数weak_ptr弱指针不会控制影响对象的生命周期不会改变对象的引用计数,shared_ptr释放指向对象时是不会考虑weak_ptr是否指向该对象weak_ptr不是独立指针不能单独操作所指向的资源不配拥有对象,更不能指向一个新的空间 作用
weak_ptr指针一般用来辅助shared_ptr的使用监视shared_ptr指向对象的生命周期weak_ptr和shared_ptr之间可以相互转换shared_ptr可以直接赋值给weak_ptr但是反过来是行不通的需要使用lock函数。
本文涉及的所有程序
00_code.cpp
#include iostream
#include memoryusing namespace std;class A
{
public:A(){cout A endl;}A(int num) : m_num(num){cout A int endl;}A(const A other) : m_num(other.m_num){cout A move int endl;}~A(){cout ~A endl;}public:int m_num;
};int main(int argc, char const* argv[])
{shared_ptrA pa(new A(5));weak_ptrA wpa pa;weak_ptrA wpa2 pa;weak_ptrA wpa3 pa;// weak_ptr常用功能auto pb wpa.lock();if (pb nullptr){cout pb is nullptr endl;}// use_count();返回的是shared_ptr的引用计数cout wpa.use_count() endl;// expired():判断当前弱指针指向的对象是否被释放if (wpa.expired()){cout wpa pointer class is free endl;}wpa.reset();return 0;
}01_code.cpp
#include iostream
#include memoryusing namespace std;class Child;class Parent
{
public:Parent(){cout Parent endl;}~Parent(){cout ~Parent endl;}//shared_ptrChild c;weak_ptrChild c;
};class Child
{
public:Child(){cout Child endl;}~Child(){cout ~Child endl;}shared_ptrParent p;
};int main(int argc, char const* argv[])
{shared_ptrParentpp(new Parent());//pp:1shared_ptrChildcc(new Child());//cc:1//循环引用pp-c cc;//cc:1 pp:1cc-p pp;//pp:2 cc:1cout pp.use_count()endl;cout cc.use_count() endl;return 0;
}02_code.cpp
#include iostream
#include memoryusing namespace std;int main(int argc, char const *argv[])
{shared_ptrint p(new int(5));weak_ptrint wp p;//shared_ptr/weak_ptr的尺寸大小是裸指针的两倍cout sizeof(int *) endl;cout sizeof(p) endl;cout sizeof(wp) endl;return 0;
}03_code.cpp
#include iostream
#include memoryusing namespace std;class A:public enable_shared_from_thisA
{
public:A(){cout A endl;}A(int num) : m_num(num){cout A int endl;}A(const A other) : m_num(other.m_num){cout A move int endl;}shared_ptrA getAddr(){//return shared_ptrA(this);return shared_from_this();//返回可共享的this指针}~A(){cout ~A endl;}public:int m_num;
};int main(int argc, char const *argv[])
{// A a;// shared_ptrAtemp(a);// shared_ptrA temp a.getAddr();// int num 5;// shared_ptrintp(num);//shared_ptrA pa(new A());A *pa new A();shared_ptrA temp pa-getAddr();return 0;
}使用说明
在VS2022中进行调试执行完第一条语句后pa的强引用计数加1 执行完第二句的弱指针赋值后发现多了一个弱引用计数和强引用计数一样都为1 增加pa.reset()的操作。通过调试可以发现不关心是否有弱指针指向当前对象只要指向当前的指针强引用计数为0了当前对象就会调用析构函数释放空间。 weak_ptr无法指向一个新的空间只能指向已有的智能指针它不配拥有一个对象只能作为一个指向 weak_ptr不可以直接赋值给shared_ptr weak_ptr的常规操作
lock();
获取弱指针指向的对象对应的共享指针如果指向的对象释放那么返回一个nullptr
调用lock函数来获得shared_ptr如果对象已经被释放则返回一个空的shared_ptr
有些书上叫做将弱指针转换为共享指针 在VS2022下调试结果如下
在调用lock前pa的强引用计数为1 在调用lock后pa的强引用计数变为2 use_count();
功能返回有多少个shared_ptr智能指针指向某对象引用计数的个数
用途主要用于调试 expired();
判断弱指针是否过期所指向的对象是否被释放true/false reset();
将该弱指针设置为空弱引用计数减1强引用计数不变
执行wpa.reset前弱引用计数为3强引用计数为2 执行wpa.reset后弱引用计数减1变为2强引用计数仍为2 shared_ptr weak_ptr
尺寸
shared_ptr和weak_ptr一样大是裸指针的两倍 智能指针结构框架
从中可以发现智能指针实际上由两个指针组成一个指针指向数据一个指针指向控制块 常见使用问题
shared_ptr多次引用同一数据会导致两次释放同一内存只涉及shared_ptr
int* pInt new int[100];shared_ptr sp1(pInt);// 一些其它代码之后…shared_ptr sp2(pInt);
shared_ptr循环引用导致内存泄露涉及shared_ptr和weak_ptr
我们定义了两个类Parent和Child两个类没有继承关系在Parent中定义了一个Child的智能指针在Child中定义了一个指向Parent类型的智能指针 在main函数中定义分别定义Parent和Child类型的指针让它们内部的指针互相指向 这样就产生了循环引用的现象 编译报错这是由于未前置声明Child类Parent类中找不到Child 加上前置声明 重新编译运行结果如下发现两个类只构造了没有析构释放导致了内存泄漏 通过VS2022调试可以发现两个main中的智能指针在循环引用后引用计数都变成了2。在程序运行结束时main中的两个智能指针释放了之后引用计数减1后变为1大于0而两个在类中定义的智能指针由于它们属于类中的属性它们必须在析构函数被调用了才能释放而程序结束引用计数不为0也就无法调用析构函数。因此这样就导致了内存泄漏。 以图示说明如下 解决方法我们将类中的两个指针随便一个改为weak_ptr
如图我修改的是Parent中的指针运行发现两个对象空间可以被正常释放
分析由于Parent类中的是weak_ptr因此执行完p-c cc;cc-p pp;后cc的强引用计数不变仍为1pp的强引用计数为2当main中的return 0;执行完之后局部变量释放pp引用计数变成1cc引用计数变为0从而会调用Child的析构函数将Child类中的shared_ptrp释放因此pp的引用计数也变为0最终调用Parent的析构函数将全部空间释放掉。 shared_ptr指向局部变量的地址会导致两次释放同一个内存只涉及shared_ptr
我们在类中定义了一个函数用于返回当前对象的地址其中this指针使用shared_ptr进行包装。 在main中实例化一个对象并用一个智能指针来获取对象地址。
发现报错段错误局部对象被释放了两次 这是由于a是局部对象它在程序运行结束的时候会自己调用析构函数进行释放而temp是指向这个局部变量的智能指针它在程序结束的时候会再次释放局部变量因此导致了空间被释放两次产生了段错误。与下图情况一模一样 同样使用智能指针接收对象的this指针也不行 解决方法
通过裸指针申请空间的方法实例化对象然后再用智能指针接收对象返回值 shared_ptr接收shared_ptr所实例化对象的this指针导致会导致两次释放同一个内存只涉及shared_ptr
继续以上面的class A为例通过智能指针实例化从堆区new出来的对象通过智能指针接收对象的this指针也会导致空间被释放两次 解决方法
针对通过智能指针实例化从堆区new出来的对象通过智能指针接收对象的地址。而对于任何局部变量此方法无效我们也可以使用上面的方法直接使用裸指针从堆区实例化对象
我们需要继承一个模板类enable_shared_from_this并将要返回的this指针改为shared_from_this()此方法可以返回可共享的this指针 运行结果