【C++】C++的单例模式、跟踪内存分配的简单方法

二十四、C++的单例模式、跟踪内存分配的简单方法

1、C++的单例模式
本小标题不是讨论C++的语言特性,而是一种设计模式,用于确保一个类在任何情况下都只有一个实例,并提供一个全局访问点来获取这个实例。即C++的单例模式。这种模式常用于资源管理,如‌线程池、‌缓存、‌日志对象等,以确保这些关键资源不会被过度使用,同时节省内存。单例模式的核心在于类自身负责创建自己的唯一实例,并提供一个静态方法来获取这个实例,从而防止外部代码创建多个实例。‌

(1)关于单例模式的一点说明:
单例模式说白了就是,我只想有一个对象的单一实例。也就是只想有一个对象的单一的数据集,比如一些专属它的变量,和一些仅针对它的函数。当然这些函数也是仅仅针对这个对象的、特定的数据集的操作。
那么,要实现单例模式,至少有下面三种实现途径:
一是用类来实现。像Java和C#它们天生就是面向对象语言,所以它们强制你使用类。特别是java,所有东西都必须是一个类,你不能在类之外有代码,如果你想要静态的功能,你不需要实例化,但你必须在你的类中创建静态成员。
二是可以用命名空间来实现。C++不像Java和C#那么多规则限制,C++不对静态函数做这些规则限制,所以C++可以不需要写一个类,可以在某个名称空间中写一些函数,甚至在全局名称空间中,它们不属于任何类的类型。其实说白了,类名就是一种命名空间。用类来实现单例模式,从根本上说,就是将类用作命名空间,来调用某些函数。
三是,C++可以有完全全局的变量,或者可以有一个静态变量,它被绑定到一个特定的翻译单元,或者一个特定的CPP文件。也是可以实现单例模式的。

所以要实现单例模式并不一定非得用类来实现,只是用类实现是最简单直观的。

(2)单例设计模式在哪里发挥作用呢?
当我们想要拥有应用于某种全局数据集的功能,而且我们只是想要重复使用时,单例是非常有用的。比如一个随机数生成器,我们只是希望能够查询它,比如给我们一个随机数,我们不需要实例化它,遍历所有东西。因为我们只是想实例化它一次,这样它就会生成随机数生成器的种子,建立起它所需要的任何辅助的东西了。然后我们要调用一个函数,基于我们初始化它的结果,它会给我们一个随机数。
另一个很好的例子是渲染器,渲染器通常是一个非常全局的东西。我们通常不会有一个渲染器的多个实例,我们有一个渲染器,我们向它提交所有这些渲染命令,然后它会为我们渲染一些东西。如果我们将其分解到opengl的部分,我们实际上通过渲染器调用opengl调用的东西,本身就是一组全局函数。这根本不是和某种对象有关的东西,它们只是C风格的函数,没有类,一点关系都没有。

‌‌(3)用类实现单例模式的几个关键点:
发明类的初心就是重复使用,创建任意个实例的,但是现在我们只允许它只能有一个实例,所以我们要通过下面几点来达到目的:
一是私有构造函数‌:防止外部通过new操作符创建多个实例,因为new操作符的底层也是调用构造函数,私有构造函数就无法调用。
‌‌二是使用静态变量‌存储类的唯一实例。
‌三是使用公共静态方法‌提供一个全局访问点来获取这个实例。

下面编写一个非常非常基本的、用类来实现单例的例子:

这段代码通过将构造函数设为私有,确保外部无法直接创建实例;创建一个自身的实例,并静态的、私有的存储;然后通过一个公共的静态方法来获取那个实例。这些操作就让这个类成了一个单例类。

可见,C++中的类单例只是一种组织一堆全局变量和静态函数的方式,这些静态函数有时可能对这些变量起作用,有时也可能不对这些变量起作用。也就是在一个单一的名称空间下(类名),把这些全局变量和静态函数组织在一起。这就是C++类单例的本质

如果还是不是太理解的同学可以参考我之前写的博文 【C++】类、静态static、枚举、重载、多态、继承、重写、虚函数、纯需函数、虚析构函数_静态与多态:重写、重载、模板-CSDN博客 中的static部分,相信看完就明白了。

如果觉得上面的例子没有啥意义,那我们利用单例类写一个随机数生成器:

这个随机数生成器是我们在一开始就放入了随机数种子,然后在整个程序中重用,非常简单,因为我们不需要一个随机数生成器有多个实例。上图单例仅仅是返回了一个静态值,所以这个单例可以写成右边的静态函数。但是我们还是使用了类单例(左图),因为类单例之所以为类单例,是因为它实际上还是一个类,因此它可以支持所有的类特性,比如类成员变量等。

如果说上面需要调用GetInstance再调用get_seed很麻烦,我们可以这样改写:

如果说上面的写法还是特别麻烦,我们还可以这样写:

此时左图的写法就清晰很多,不需要像右图那样,三步分散得到处都是,可读性比较差。

结论:单例的核心就是上面的GetInstance函数。单例的声明周期就是你的应用的生命周期。一旦我有了这个单例,我可以写任何数量的非静态方法,都可以通过GetInstance函数访问这些方法。

下面再简单展示一下使用命名空间实现的写法:

虽然使用命名空间也可以实现,但是失去了public、private这些类的功能。

2、跟踪内存分配的简单方法
如何跟踪内存的分配?这个知识点其实前面都已经有过涉及,这里就是进行一个小结。

知道你的程序什么时候分配内存,特别是堆内存,是非常有用的。尤其是在性能关键的代码中,在堆上分配内存是很糟糕的做法。 如果你知道是哪行代码分配了内存,你就可以针对性的优化你的程序,使其运行得更快。此外,如果你能看到内存被分配到哪里,可以帮助你更好的理解你的代码的工作原理。所以本部分要编写代码跟踪应用程序内存的总体使用情况,而不是依赖某些内存管理工具。


所以,我们可以通过在operator new函数中插入一个断点,就可以精确的追踪这些内存分配的来源。

下面写一个完整的new和delete:

我们还可以维护一个allocation metrics,就可以确切知道有多少内存被使用,有多少内存被分配,有多少内存被释放等等:

当然上面这个可能写得比较牵强,anyway大体就是这么写的。

最后提一下,VS内置的内存分配跟踪分析工具Valgrind,是一款用于内存调试、内存泄露检测以及性能分析的软件开发工具。自己写还是使用现有的工具,这个你自己看着办吧。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LangGPT结构化提示词编写实践

基础任务 如果直接询问大模型strawberry有几个r,大模型会给出错误的答案: 这里我们引入思维连Chain of Thought,我们让大模型遍历一遍单词,每次累加得到最终结果 之前怎么都做不对的题,让大模型一步一步思考&#xf…

【Python系列】使用 Poetry 进行 Python 项目管理

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Linux内核USB2.0驱动框架分析--USB设备枚举过程

一 USB特点 1.1 USB协议版本介绍: USB1.0/1.1(low/fullspeed):传输速率最大为12Mbps,是较早的USB协议版本。 USB2.0(highspeed):传输速率最大为480Mbps,相比USB1.0/1.1…

解决ultralytics的YOLO模型训练中验证集Loss为NaN(或mAP为0)的问题

前言 在使用ultralytics库的YOLO模型时,比如YOLOv8进行目标检测模型训练,遇到一个非常奇怪的问题:训练过程中的验证损失(loss)出现了NaN,而验证的评价指标如mAP50却能正常计算(有时mAP都也为0&…

微信支付现金红包,实现转账到零钱包功能

大家好,我是小悟。 上次说到微信商家转账到零钱要出新玩法,可能会对某些特定的业务产生影响,详细请阅读【微信商家转账到零钱新玩法,却是个不好接受的消息】。 微信支付还有个现金红包的产品,也可以实现转账到用户零…

掌握均值回归,外汇交易盈利新视角

外汇交易是全球金融市场的重要组成部分,它不仅用于国际间结算债权债务,还提供了一个充满盈利机会的金融市场。在这个市场中,货币价格的波动为投资者带来了丰富的交易机会。本文,EagleTrader将详细介绍外汇交易中的一种常用策略——…

mac-泛洪

泛洪攻击的类型 TCP SYN Flood: 攻击者向目标服务器发送大量的 TCP SYN 请求,但不完成握手过程。服务器为每个请求分配资源,最终可能耗尽其连接表,导致无法处理正常请求。 UDP Flood: 攻击者向目标发送大量的 UDP 数据…

【Windows修改Docker Desktop(WSL2)内存分配大小】

记录一下遇到使用Docker Desktop占用内存居高不下的问题 自从使用了Docker Desktop,电脑基本每天都需要重启,内存完全不够用,从16g扩展到24,然后到40G,还是不够用;打开Docker Desktop 运行时间一长&#x…

【06】A-Maven项目SVN设置忽略文件

做Web项目开发时,运用的是Maven管理工具对项目进行管理,在项目构建的过程中自动生成了很多不需要SVN进行管理的文件,SVN在对源码进行版本管理时,需要将其忽略,本文给出了具体解决方案。 SVN设置忽略Maven项目中自动生成…

【数据分享】2024年我国省市县三级的生活服务设施数量(46类设施/Excel/Shp格式)

人才市场、售票处、旅行社等生活服务设施的配置情况是一个城市公共基础设施完善程度的重要体现,一个城市生活服务设施种类越丰富,数量越多,通常能表示这个城市的公共服务水平越高! 本次我们为大家带来的是我国各省份、各地级市、…

【算法】Floyd多源最短路径算法

目录 一、概念 二、思路 三、代码 一、概念 在前面的学习中,我们已经接触了Dijkstra、Bellman-Ford等单源最短路径算法。但首先我们要知道何为单源最短路径,何为多源最短路径 单源最短路径:从图中选取一点,求这个点到图中其他…

【商用存储】希捷磁盘阵列部署实践

文章目录 一、前言1、盘阵类型2、性能规格 二、功能说明1、RAID配置1.1、虚拟池(virtual pool)1.2、线性池(linear pool) 2、磁盘休眠2.1、RBOD2.1.1、功能说明2.1.2、规格限制 3、ADAPT配置3.1、说明3.2、规格限制3.3、配置建议3…

Android Room框架使用指南

Room框架使用指南 项目效果创建应用,配置Gradle1、在app Module的build.gradle配置kapt插件2、配置依赖:3、配置依赖包版本号创建实体类创建DAO1、DAO简介2、WordDao设计以及相关注解说明3、监听数据变化添加Room数据库1、Room数据库简介2、实现Room数据库实现存储库实现View…

Read excerpt(eighteen)——The hidden value of Corporate Social Responsibility

“There is one and only one social responsibility of businesses,” wrote Milton Friedman, a Nobel prize-winning economist, “That is, to use its resources and engage in activities …

纯血鸿蒙系统 HarmonyOS NEXT自动化测试实践

1、测试框架选择 hdc:类似 android 系统的 adb 命令,提供设备信息查询,包管理,调试相关的命令ohos.UiTest:鸿蒙 sdk 的一部分,类似 android sdk 里的uiautomator,基于 Accessibility 服务&…

基于java宠物医院管理系统的设计与实现

一、环境信息 开发语言:JAVA JDK版本:JDK8及以上 数据库:MySql5.6及以上 Maven版本:任意版本 操作系统:Windows、macOS 开发工具:Idea、Eclipse、MyEclipse 开发框架:SpringbootHtmljQueryMysql…

施工企业为什么要用工程项目管理软件?工程项目管理软件的用处是什么?

施工企业一定会遇到哪些问题?工人怠工、材料浪费、数据造假、工期拖延、质量问题、安全隐患等。这些问题正在悄然侵蚀建施工业的经济效益。每一个环节的失控都可能导致巨大的经济损失,还可能损害企业的声誉。面对日益复杂的工程管理环境,如何…

业务模块部署

一、部署前端 1.1 window部署 下载业务模块前端包。 (此包为耐威迪公司发布,请联系耐威迪客服或售后获得) 包名为:业务-xxxx-business (注:xxxx为发布版本号) 此文件部署位置为:……

【Web前端】OOP编程范式

面向对象编程(Object-Oriented Programming,简称 OOP)是一种程序设计思想,它通过将程序视为一组相互作用的对象来设计程序。OOP 提出了一些重要的基本概念,包括类与实例、继承和封装。面向对象编程将系统视为由多个对象…

C++入门基础知识142—【关于C++ 友元函数】

成长路上不孤单😊😊😊😊😊😊 【14后😊///C爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于C 友元函数的相关内容! 关于…