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

news2025/1/16 17:55:34

异步编程中存在一种场景,需要在类中将该类的对象注册到某个回调类或函数中,不能简单地将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为共享指针sp1
		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 << "代码块【3】结束" << std::endl;
	}
	
	system("pause");
	return 0;
}

在这里插入图片描述

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

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

相关文章

【变压器故障诊断分类及预测】基于GRNN神经网络

课题名称&#xff1a;基于GRNN神经网络的变压器故障诊断分类及预测 版本日期&#xff1a;2024-02-10 运行方式&#xff1a;直接运行GRNN0507.m文件 代码获取方式&#xff1a;私信博主或QQ&#xff1a;491052175 模型描述&#xff1a; 对变压器油中溶解气体进行分析是变压器…

基于springboot+vue的精准扶贫管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

前端工程化面试题 | 15.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Linux系统前后端分离项目

目录 一.jdk安装 二.tomcat安装 三.MySQL安装 四.nginx安装 五.Nginx负载均衡tomcat 六.前端部署 一.jdk安装 1. 上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录&#xff0c;将安装包拖进去 2. 解压安装包 这里需要解压到usr/local目录下&#xff0c;在这里新建一个…

基于yolov5的电瓶车和自行车检测系统,可进行图像目标检测,也可进行视屏和摄像检测(pytorch框架)【python源码+UI界面+功能源码详解】

功能演示&#xff1a; 基于yolov5的电瓶车和自行车检测系统_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的电瓶车和自行车检测系统是在pytorch框架下实现的&#xff0c;这是一个完整的项目&#xff0c;包括代码&#xff0c;数据集&#xff0c;训练好的模型…

低于API等级30的应用将无法在上述应用商店

minSdkVersion minSdkVersion用于指定应用兼容的最低Android版本&#xff08;API等级&#xff09;。 如果APP某些功能无法支持低版本Android系统的设备&#xff0c;可以配置minSdkVersion确保APP只能安装到指定Android版本以上的设备。HBuilder|HBuilderX中可在manifest.json中…

单词倒排——c语言解法

以下是题目&#xff1a; 这个题中有三个点&#xff0c; 一个是将非字母的字符转换为空格&#xff0c; 第二是如果有两个连续的空格&#xff0c; 那么就可以将这两个连续的空格变成一个空格。 第三个点就是让单词倒排。 那么我们就可以将这三个点分别封装成三个函数。 还有就是…

Spring Security源码学习

Spring Security本质是一个过滤器链 过滤器链本质是责任链设计模型 1. HttpSecurity 【第五篇】深入理解HttpSecurity的设计-腾讯云开发者社区-腾讯云 在以前spring security也是采用xml配置的方式&#xff0c;在<http>标签中配置http请求相关的配置&#xff0c;如用户…

Linux下的版本控制系统——Git:初学者指南

引言 在软件开发的世界中&#xff0c;版本控制是一项至关重要的技术。它允许开发者追踪和管理代码的变更历史&#xff0c;协同工作&#xff0c;并在必要时恢复到之前的版本。而在Linux系统下&#xff0c;Git已经成为事实上的版本控制标准。本文将带领大家走进Git的世界&#x…

【人脸朝向识别与分类预测】基于PNN神经网络

课题名称&#xff1a;基于PNN神经网络的人脸朝向识别分类 版本日期&#xff1a;2024-02-20 运行方式&#xff1a;直接运行PNN0503.m文件 代码获取方式&#xff1a;私信博主或 QQ:491052175 模型描述&#xff1a; 采集到一组人脸朝向不同角度时的图像&#xff0c;图像来自不…

React组件详解

React组件分为两大类 1.函数组件 2.类组件&#xff08;最常用&#xff09; 组件化 import ReactDom from "react-dom";// // 1.通过函数创建一个组件 // 2.函数名字必须大写开头 // 3.函数必须有返回值 function Func1() {return <h2>这是一个基础组件</h…

[设计模式Java实现附plantuml源码~行为型]对象间的联动~观察者模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

数字化转型导师鹏:政府数字化转型政务服务类案例研究

政府数字化转型政务服务类案例研究 课程背景&#xff1a; 很多地方政府存在以下问题&#xff1a; 不清楚标杆省政府数字化转型的政务服务类成功案例 不清楚地级市政府数字化转型的政务服务类成功案例 不清楚县区级政府数字化转型的政务服务类成功案例 课程特色&#x…

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…

2023最新盲盒交友脱单系统源码

源码获取方式 搜一搜&#xff1a;万能工具箱合集 点击资源库直接进去获取源码即可 如果没看到就是待更新&#xff0c;会陆续更新上 或 源码软件库 最新盲盒交友脱单系统源码&#xff0c;纸条广场&#xff0c;单独抽取/连抽/同城抽取/高质量盒子 新增功能包括心动推荐&#xff…

JavaAPI常用类02

目录 基本数据类型封装类 包装类常用属性方法 8中基本数据类型各自所对应的包装类 以下方法以java.lang.Integer为例 代码 运行 装箱和拆箱 装箱 何为装箱 代码 范围问题 代码 运行 拆箱 代码 String类 概述 代码 运行 创建形式 画图讲解 代码 运行 构造…

golang通过http访问外部网址

不同项目之前,通过http访问,进行数据沟通 先设定一个接口,确认外部能访问到 PHP写一个接口 public function ceshi_return() {$data $this->request->param();$id $data[id];$res Db::name(user)->field(id,status,price,name)->where([id>$id])->find…

数据可视化基础与应用-01-课程目标与职位分析

总结 本系列是数据可视化基础与应用的第01篇&#xff0c;主要介绍本门课程的课程目标与职位分析 教材 数据可视化基础与应用 课程教学方法 布鲁姆教学法 认知领域&#xff08;cognitive domain&#xff09; 1.知道&#xff08;知识&#xff09;&#xff08;knowledge&#…

Jitsi Meet 大型视频会议调优方案

jitsi meet 大型视频会议调优方案 在举办一些大型会议的时候,比如100个人会议,为了节约宽带和节省资源,我们并不会选择传输全部的音视频资源。 举个例子,比如100个人线下会议,如果大家都说话的情况下,大家要么听不清,要么听得是声音最大的那几个人。 视频会议也可以借…

数据结构之顺序表链表

一、线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直…