C++11的weak_ptr弱引用的智能指针

        弱引用指针weak_ptr是用来监视shared_ptr的,不会使引用计数器加1,它不管理shared_ptr内部的指针,主要是为了监视shared_ptr的生命周期,更像是shared_ptr的一个助手。weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,主要是为了通过shared_ptr获得资源的监测权,它的构造函数不会增加引用计数,它的析构不会减少引用计数,纯粹只是作为一个旁观者来监视shared_ptr中管理的资源是否存在。weak_ptr还可以用来返回this指针和解决循环引用的问题。

weak_ptr基本用法

        1、通过use_count()方法来获得当前观测资源的引用计数,代码如下:

#include <memory>
#include <iostream>
using namespace std;int main()
{shared_ptr<int> sp(new int(1));weak_ptr<int> wp(sp);///输出1cout << sp.use_count() << endl;///输出1cout << wp.use_count() << endl;shared_ptr<int> sp2(new int(2));sp2 = sp;///输出2cout << sp.use_count() << endl;return 0;
}

        2、通过expired()方法来判断所检测的资源是否已经被释放,代码如下:

 #include <memory>
#include <iostream>
using namespace std;int main()
{shared_ptr<int> sp(new int(1));weak_ptr<int> wp(sp);if (wp.expired()){cout << "weak_ptr无效,所监视的智能指针被释放" << endl;}else{cout << "weak_ptr 有效" << endl;}return 0;
}

        3、通过lock方法来获取所监视的shared_ptr,代码如下:


#include <memory>
#include <iostream>
using namespace std;std::weak_ptr<int> gw;void f()
{if (gw.expired())   ///所监听的shared_ptr是否被释放{cout << "gw is exipired" << endl;}else{auto spt = gw.lock();cout << *spt << endl;}
}int main()
{{shared_ptr<int> sp(new int(1));gw = sp;f();}f();return 0;
}

         输出如下:

1
gw is expired

weak_ptr返回this指针

        不能直接将this指针返回为shared_ptr,需要通过派生std::enable_shared_from_this类,并通过其方法shared_from_this来返回智能指针,原因是std::enable_shared_from_this类中有一个weak_ptr,这个weak_ptr用来观测this指针,调用shared_from_this()方法时,会调用内部这个weak_ptr的lock()方法,将所观测的shared_ptr返回,看下面代码:

#include <memory>
#include <iostream>
#include <string>
#include <string.h>
using namespace std;struct A : public std::enable_shared_from_this<A>
{shared_ptr<A> GetSelf(){return shared_from_this();}///析构函数调用了1次~A(){cout << "delete A" << endl;}
};int main()
{shared_ptr<A> sp1(new A);shared_ptr<A> sp2 = sp1->GetSelf();return 0;
}

        输出结果如下:

deleted A

        在外面创建A对象的智能指针和通过该对象返回this的智能指针都是安全的,因此shared_from_this是内部的weak_ptr调用lock()方法之后返回的智能指针,在离开作用域之后,sp1的引用计数减为0,A对象会被析构,不会出现A对象被析构两次的问题。

weak_ptr解决循环引用问题

        智能指针的循环引用会导致内存泄漏问题,请看下面的代码:

#include <memory>
#include <iostream>
#include <string>
#include <string.h>
using namespace std;struct A;
struct B;struct A
{std::shared_ptr<B> bptr;~A(){cout << "A is deleted" << endl;}
};struct B
{std::shared_ptr<A> aptr;~B(){cout << "B is deleted" << endl;}
};int main()
{{///析构函数没有被调用shared_ptr<A> ap(new A);shared_ptr<B> bp(new B);ap->bptr = bp;bp->aptr = ap;///引用计数为2cout << "ap use_count: " << ap.use_count() << endl;cout << "bp use_count: " << bp.use_count() << endl;}return 0;
}

        在这个例子中,由于循环引用导致ap和bp的引用计数都为2,离开作用域之后引用计数减为1,不会去删除指针,导致内存泄漏。通过weak_ptr就可以解决这个问题,只要将A或者B的任意一个成员变量改为weak_ptr即可。

struct A;
struct B;struct A
{std::shared_ptr<B> bptr;~A(){cout << "A is deleted" << endl;}
};struct B
{std::weak_ptr<A> aptr;~B(){cout << "B is deleted" << endl;}
};int main()
{{shared_ptr<A> ap(new A);shared_ptr<B> bp(new B);ap->bptr = bp;bp->aptr = ap;///引用计数为1cout << "ap use_count: " << ap.use_count() << endl;cout << "bp use_count: " << bp.use_count() << endl;}return 0;
}

        输出如下:

ap use_count: 1
bp use_count: 2
A is deleted
B is deleted

        这样在对B的成员赋值时,即执行bp->aptr = ap;时,由于aptr是weak_ptr,它并不会增加引用计数,所以ap的引用计数仍然会是1,在离开作用域之后,ap的引用计数会减少为0,A指针会被析构,析构后其内部的ptr的引用计数为减为1,然后再离开作用域后bp引用计数又从1减到0,B对象也会被析构,不会发生内存泄漏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/157957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows对话框

windows对话框有以下几种&#xff1a; HWND CreateDialogParamA([in, optional] HINSTANCE hInstance,[in] LPCSTR lpTemplateName,[in, optional] HWND hWndParent,[in, optional] DLGPROC lpDialogFunc,[in] LPARAM dwInitParam );HWND Cr…

软信天成:如何利用大数据提高客户体验?

当今社会&#xff0c;市场均势正在发生变化&#xff0c;消费者拥有更多的选择和更高的决定权&#xff0c;传统的市场营销技巧注重提高品牌认知度和吸引潜在客户&#xff0c;现在早已过时。经济不确定性弥漫&#xff0c;数字化转型仍是大多数企业的优先选择&#xff0c;新的竞争…

Go 学习

文章目录 Go 语言中的值类型Go 语言中的引用类型 指针的使用二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人…

记录一次hiveserver2和namenode进程宕掉的排查

背景 最近发现集群主节点总有进程宕机&#xff0c;定位了大半天才找到原因&#xff0c;分享一下 排查过程 查询hiveserver2和namenode日志&#xff0c;都是正常的&#xff0c;突然日志就不记录了&#xff0c;直到我重启之后又恢复工作了。 排查各种日志都是正常的&#xff0…

Vue3 插槽 v-slot

插槽 视频链接&#xff1a;尚硅谷vue-插槽章节 不使用插槽的情况下 结果&#xff1a; 1 默认插槽 在子组件中只能有一个 结果&#xff1a; 2 具名插槽 #b是v-slot:b 的缩写 顾名思义就是指着名字去插入 结果&#xff1a; 3 作用域插槽 可以传递数据的插槽&#…

分享一些简单的英语问候语

昨天和一个朋友聊天&#xff0c;他问我最近有没有某个国家的客户&#xff1f;我说只有一两个&#xff0c;都已经好久没有联系了&#xff0c;上一次问候还是在九月份。他说从十月底开始就收到很多来自当地的询盘&#xff0c;你不妨问下客户最近是否有新的需求&#xff1f; 于是…

python 实现蚁群算法(simpy带绘图)

这里使用了蚁群算法求解了旅行商问题&#xff0c;同时结合了simpy来绘图 选择下一个食物的函数为&#xff1a; probability[i] pheromone[self.now][self.not_to_foods[i]] ** pheromone_w (1 / distance[self.now][self.not_to_foods[i]]) ** distance_w 该条路概率权重该点…

idea pom导入net.sf.json的jar包失败

开始在pom.xml文件中加入依赖如下 <dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.2.3</version> </dependency> maven reload project后&#xff0c;项目一直报&#xff1a;…

排序算法--插入排序

实现逻辑 ① 从第一个元素开始&#xff0c;该元素可以认为已经被排序 ② 取出下一个元素&#xff0c;在已经排序的元素序列中从后向前扫描 ③如果该元素&#xff08;已排序&#xff09;大于新元素&#xff0c;将该元素移到下一位置 ④ 重复步骤③&#xff0c;直到找到已排序的元…

【python基础】random模块常用方法讲解

文章目录 前言random常用方法random.random()random.uniform(a,b)random.randint(a,b)random.randrange([start], stop[, step])random.choice(sequence)random.shuffle(x,[random])random.sample(sequence,k) 前言 Python标准库中的random函数&#xff0c;可以生成随机浮点数…

【数据结构】树与二叉树(十八):树的存储结构——Father链接结构、儿子链表链接结构

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语 5.2 二叉树5.3 树5.3.1 树的存储结构1. 理论基础2. 典型实例 5.3.2 Father链接结构a. 定义树节点结构b. 创建新节点c. 主函数d. 代码整合 5.3.3 儿子链表链接结构a. 定义树节点结构b. 创建新节点c. 添加…

为什么录屏没声音?实用技巧大放送!

录屏已成为我们在数字时代记录和分享内容的重要方式之一。但有时&#xff0c;您可能会遇到录制视频却没有声音的问题。这个问题可能出现在不同的录屏软件中&#xff0c;导致许多人感到疑惑。在本文中&#xff0c;我们将探讨为什么录屏没声音&#xff0c;并提供两种解决方案&…

C语言实现堆栈和队列(动态)

行路难&#xff01;行路难&#xff01;多歧路&#xff0c;今安在&#xff1f;长风破浪会有时&#xff0c;直挂云帆济沧海。————李白 一 .堆栈 1 什么是堆栈 堆栈是一种特殊的线性表&#xff0c;堆栈中的元素以及元素之间的逻辑关系和线性表完全相同。在操作上的差别是线性…

springboot+jsp+bootstrap+java问卷调查系统

系统功能需求包含业务需求和功能需求&#xff0c;系统功能需求分析是在了解用户习惯、开发人员技术和实力等各个因素的前提下&#xff0c;对其进行深入分析&#xff0c;了解系统基本需求后&#xff0c;基本功能如下&#xff1a; 本课题要求实现优质的问卷调查系统&#xff0c;就…

安全框架springSecurity+Jwt+Vue-2(后端开发)

一、创建项目及配置 ①&#xff1a;创建新的项目及常用包 ②&#xff1a;引入依赖和配置 devtools&#xff1a;项目的热加载重启插件 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId&…

如何配置ESB单据集成接口

ESB企业服务总线在实际项目中主要用于各业务系统之间的集成&#xff0c;集成包括数据集成、应用集成以及业务单据集成等&#xff0c;ESB企业服务总线主要包含三部分&#xff1a;ESB设计器、SMC管理控制台以及Server运行环境&#xff0c;ESB设计器用于服务以及集成流程的开发&am…

【C++ 设计模式】面向对象设计原则 Template Method 模式 Strategy 策略模式

一、面向对象设计原则 重新认识面向对象 理解隔离变化 • 从宏观层面来看&#xff0c;面向对象的构建方式更能适应软件的变化&#xff0c; 能将变化所带来的影响减为最小 各司其职 • 从微观层面来看&#xff0c;面向对象的方式更强调各个类的“责任” • 由于需求变化导…

Tesco EDI需求分析

Tesco&#xff0c;成立于1919年&#xff0c;是一家全球领先的综合性零售企业&#xff0c;总部位于英国。公司致力于提供高质量、多样化的商品和服务&#xff0c;以满足客户的需求。Tesco的使命是通过创新和卓越的客户服务&#xff0c;为客户创造更美好的生活。多年来&#xff0…

vue2.x源码刨析-new Vue的时候做了什么(手写简易版01)

本篇文章大致的介绍一下new Vue的过程&#xff0c; 首先我们在生成一个Vue实例化对象的时候&#xff0c;一般会这样写&#xff1a; <div id"app" style"color: red">{{name}} dep {{age}} dep {{name}}</div> const vm new Vue({data() {ret…

【idea】解决idea 执行maven build总下载 Downloading maven-metadata.xml文件

可以看到如下日志中打印了执行的命令行&#xff0c;其中包含 --update-snapshots&#xff0c;是强制更新的意思。 日志内容如下&#xff1a; D:\env\jdk1.8.0_261\bin\java.exe --update-snapshots -s D:\env\apache-maven-3.8.6\conf\settings.xml -Dmaven.repo.localD:\env\…