奇异递归模板模式应用6-类模板enable_shared_from_this

异步编程中存在一种场景,需要在类中将该类的对象注册到某个回调类或函数中,不能简单地将this传递给回调类中,很可能因为回调时该对象不存在而导致野指针访问(也有可能在析构函数解注册时被回调,造成对象不完整)。若通过智能指针管理对象,也不能直接将this构造成shared_ptr,因为无法通过裸指针获得引用计数块信息(而侵入式智能指针的引用计数块和对象内存连续,可以简单地通过偏移引用计数块大小得到),强行构造会导致对象内存多次释放。《C++20高级编程》

书中用例

struct Obj {void submit() {// 内存风险,无法通过裸指针获得引用计数块信息executor.submit([this]{ this->onComplete(); });}
}
// 奇异递归模板模式
struct Obj : enable_shared_from_this<Obj> {void submit() {// weak_from_this()获得this指针的弱指针executor.submit([obj = weak_from_this()]{// lock提升至共享指针if (auto spObj = obj.lock()) {spObj->onComplete();}});}
}

下面演示一下书中说的无法通过裸指针获得引用计数块信息的含义
1、错误示例:

class A
{
public:A() { std::cout << "A的构造函数" << std::endl; }~A() { std::cout << "A的析构函数" << std::endl; }std::shared_ptr<A> getSharedPtr() { return std::shared_ptr<A>(this); }
};int main()
{{// 演示shared_ptr的正确用法(推荐使用std::make_shared()构造,能够使得引用计数块和对象在内存上连续)std::cout << "代码块【1】开始" << std::endl;A *pa = new A();std::shared_ptr<A> sp1(pa);std::cout << "A的引用计数,sp1.use_count() = " << sp1.use_count() << std::endl;std::shared_ptr<A> sp2(sp1);std::cout << "A的引用计数:sp2.use_count() = " << sp2.use_count() << std::endl;std::cout << "代码块【1】结束" << std::endl;}{std::cout << "代码块【2】开始" << std::endl;A *pa = new A();std::shared_ptr<A> sp1(pa);std::cout << "A的引用计数,sp1.use_count() = " << sp1.use_count() << std::endl;std::shared_ptr<A> sp2(pa);std::cout << "A的引用计数:sp2.use_count() = " << sp2.use_count() << std::endl;std::shared_ptr<A> sp3(pa->getSharedPtr());std::cout << "A的引用计数:sp3.use_count() = " << sp3.use_count() << std::endl;std::cout << "代码块【2】结束" << std::endl;}system("pause");return 0;
}

在这里插入图片描述
代码块【1】中使用了共享指针的拷贝操作,引用计数是正确的。而代码块【2】中的三个共享指针都是用裸指针pa初始化的,那么得到的三个共享指针sp1、sp2和sp3各不相干,各自维护着自己的引用计数,因而引用计数都是1。也就是书中说的“无法通过裸指针获得引用计数块信息”。
由于引用计数错误,那么在代码块【2】结束的时候,这三个共享指针sp1、sp2和sp3都将释放内存,就会导致内存要被释放3次,这显然会让程序崩溃。因此在第二次释放内存时,程序崩溃,所以图中打印信息只显示2行“A的析构函数”。
2、正确示例

class A : public std::enable_shared_from_this<A>
{
public:A() { std::cout << "A的构造函数" << std::endl; }~A() { std::cout << "A的析构函数" << std::endl; }std::shared_ptr<A> getSharedPtr() { return weak_from_this().lock(); }
};int main()
{{std::cout << "代码块【3】开始" << std::endl;A *pa = new A();std::shared_ptr<A> sp1(pa);std::cout << "A的引用计数,sp1.use_count() = " << sp1.use_count() << std::endl;std::shared_ptr<A> sp2(sp1); // 修改代码块【2】的裸指针pa为共享指针sp1std::cout << "A的引用计数:sp2.use_count() = " << sp2.use_count() << std::endl;std::shared_ptr<A> sp3(pa->getSharedPtr());std::cout << "A的引用计数:sp3.use_count() = " << sp3.use_count() << std::endl;std::cout << "代码块【3】结束" << std::endl;}system("pause");return 0;
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

[VNCTF2024]-Web:CheckIn解析

查看网页 一款很经典的游戏&#xff0c;而且是用js写的 在调试器里面我们可以看见&#xff0c;如果游戏通关的话&#xff0c;它会进行一系列操作&#xff0c;包括使用console.log(_0x3d9d[0]);输出_0x3d9d[0]到控制台&#xff0c;那我们就直接在点击在控制台求出它的值

初始Nginx(基本概念)

目录 一、Nginx的概念 二、Nginx常用功能 1、HTTP(正向)代理&#xff0c;反向代理 1.1正向代理 1.2 反向代理 2、负载均衡 2.1 轮询法&#xff08;默认方法&#xff09; 2.2 weight权重模式&#xff08;加权轮询&#xff09; 2.3 ip_hash 3、web缓存 三、基础特性 四…

论文阅读:Ground-Fusion: A Low-cost Ground SLAM System Robust to Corner Cases

前言 最近看到一篇ICRA2024上的新文章&#xff0c;是关于多传感器融合SLAM的&#xff0c;好像使用了最近几年文章中较火的轮式里程计。感觉这篇文章成果不错&#xff0c;代码和数据集都是开源的&#xff0c;今天仔细读并且翻译一下&#xff0c;理解创新点、感悟研究方向、指导…

挑战杯 基于大数据的股票量化分析与股价预测系统

文章目录 0 前言1 课题背景2 实现效果3 设计原理QTChartsarma模型预测K-means聚类算法算法实现关键问题说明 4 部分核心代码5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的股票量化分析与股价预测系统 该项目较为新颖…

网络安全“三保一评”深度解析

“没有网络安全就没有国家安全”。近几年&#xff0c;我国法律法规陆续发布实施&#xff0c;为承载我国国计民生的重要网络信息系统的安全提供了法律保障&#xff0c;正在实施的“3保1评”为我国重要网络信息系统的安全构筑了四道防线。 什么是“3保1评”&#xff1f; 等保、分…

爬虫入门四(抽屉半自动点赞、xpath使用、动作链、打码平台、scrapy框架介绍与安装及创建项目)

文章目录 一、抽屉半自动点赞二、xpath的使用三、动作链四、打码平台介绍超级鹰打码基本测试 五、自动登录超级鹰六、scrapy框架介绍安装创建爬虫项目 一、抽屉半自动点赞 登录抽屉账号保存cookiesimport timeimport jsonfrom selenium import webdriverfrom selenium.webdrive…

基于YOLOv5+PySide6的火灾火情火焰检测系统设计深度学习

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;225火灾 获取完整源码源文件已标注的数据集&#xff08;1553张&#xff09;配置跑起来说明 可有偿49yuan一对一远程操作&#xff0c;在你电脑跑起来 效果展示&#xff1a; ​数据集在下载的文件夹&#xff1a;yolov5-5.0\…

一键生成PDF即刻呈现:轻松创建无忧体验

在信息爆炸的时代&#xff0c;我们每天都在与各种文件、资料打交道。无论是工作中的报告、合同&#xff0c;还是学习中的笔记、论文&#xff0c;如何高效、安全地管理这些珍贵的资料&#xff0c;成为了我们迫切的需求。幸运的是&#xff0c;随着科技的发展&#xff0c;我们不再…

PX4FMU和PX4IO最底层启动过程分析(下)

PX4FMU和PX4IO最底层启动过程分析&#xff08;下&#xff09; PX4FMU的系统启动函数为nash_main(int argc,char *argv[]) PX4IO的系统启动函数为nash_start(int argc,char *argv[]) PX4FMU启动函数nash_main(int argc,char *argv[]) 首先分析一下nash_main(int argc,char *a…

五大方法教你如何分分钟构造百万测试数据!

在测试的工作过程中&#xff0c;很多场景是需要构造一些数据在项目里的&#xff0c;方便测试工作的进行&#xff0c;构造的方法有很多&#xff0c;难度和技术深度也不一样。本文提供方法供你选择。 在测试的工作过程中&#xff0c;很多场景是需要构造一些数据在项目里的&#…

【《高性能 MySQL》摘录】第 2 章 MySQL 基准测试

文章目录 2.1 为什么需要基准测试2.2 基准测试的策略2.2.1 测试何种指标 2.3 基准测试方法2.3.1 设计和规划基准测试2.3.2 基准测试应该运行多长时间2.3.3 获取系统性能和状态2.3.4 获得准确的测试结果2.3.5 运行基准测试并分析结果2.3.6 绘图的重要性 2.4 基准测试工具…

vue3 实现 el-pagination页面分页组件的封装以及调用

示例图 一、组件代码 <template><el-config-provider :locale"zhCn"><el-pagination background class"lj-paging" layout"prev, pager, next, jumper" :pager-count"5" :total"total":current-page"p…

深入浅出JVM(十)之字节码指令(下篇)

上篇文章深入浅出JVM&#xff08;九&#xff09;之字节码指令&#xff08;上篇&#xff09;已经深入浅出说明加载存储、算术、类型转换的字节码指令&#xff0c;本篇文章作为字节码的指令的下篇&#xff0c;深入浅出的解析各种类型字节码指令&#xff0c;如&#xff1a;方法调用…

计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;Cisco Packet Tracer实验 本文对应的实验报告源文件请关注微信公众号程序员刘同学&#xff0c;回复思科获取下载链接。 实验目的实验环境实验内容MAC地址、IP地址、ARP协议总线型以太网的…

2024-02-25 Unity 编辑器开发之编辑器拓展7 —— Inspector 窗口拓展

文章目录 1 SerializedObject 和 SerializedProperty2 自定义显示步骤3 数组、List 自定义显示3.1 基础方式3.2 自定义方式 4 自定义属性自定义显示4.1 基础方式4.2 自定义方式 5 字典自定义显示5.1 SerizlizeField5.2 ISerializationCallbackReceiver5.3 代码示例 1 Serialize…

音频smmu问题之smmu学习

一、音频smmu 内存访问问题 在工作中&#xff0c;遇到一个smmu问题&#xff0c;主要log信息如下&#xff1a; arm-smmu 15000000.apps-smmu: Unhandled arm-smmu context fault from soc:spf_core_platform:qcom,msm-audio-ion! arm-smmu 15000000.apps-smmu: FAR 0x0000000…

【考研数学】基础阶段习题1800和660怎么选❓

我建议以1800题为主 1800题包含基础和强化两部分&#xff0c;基础部分题量很大&#xff0c;类型也很全面&#xff0c;并且难度一点也不高&#xff0c;适合基础不好的学生来做。 660题难度比较大&#xff0c;不适合基础阶段做。 660题虽然名字叫基础训练&#xff0c;但是不适…

超详细!彻底说明白Redis持久化

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 Redis持久化方式RDBfork 函数与写时复制RDB 相关配置 AOFAOF 文件解读AOF 的写入与同步AOF 重写AOF重写的实现AOF 重写面临的问题AOF重写缓存区 AOF相关配置AOF …

车载电子电器架构 —— OEM基础技术概念开发流程

车载电子电器架构 —— 基础技术概念开发 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗…

Spring Cloud Gateway官方文档学习

文章目录 推荐写在前面一、熟悉Gateway基本概念与原理1、三大概念2、工作流程 二、基本使用路由断言的两种写法 三、路由断言工厂1、After路由断言工厂2、Before路由断言工厂3、Between路由断言工厂4、Cookie路由断言工厂5、Header路由断言工厂6、Host路由断言工厂7、Method路由…