【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,是一款用于内存调试、内存泄露检测以及性能分析的软件开发工具。自己写还是使用现有的工具,这个你自己看着办吧。
相关文章:
【C++】C++的单例模式、跟踪内存分配的简单方法
二十四、C的单例模式、跟踪内存分配的简单方法 1、C的单例模式 本小标题不是讨论C的语言特性,而是一种设计模式,用于确保一个类在任何情况下都只有一个实例,并提供一个全局访问点来获取这个实例。即C的单例模式。这种模式常用于资源管理&…...
构建一个导航栏web
<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>*{margin: 0;padding: 0;}#menu{background-color:purple;width: 100px;height: 50px;}.item{float: left;/* 浮动标签可以让块标签,…...
【Linux】Linux安全与密钥登录指南
在使用Linux服务器时,确保服务器的安全至关重要。本文将为你介绍一些关键的Linux安全措施,包括开启密钥登录、查看登录日志、限制登录IP以及查看系统中能够登录的账号。以下内容适合小白用户,通过简单的操作就能有效提升服务器的安全性。 目录…...
数据采集之scrapy框架
本博文使用基本框架完成搜房网或者其他网站的数据爬取(重点理解 scrapy 框架的构建过程,使用回调函数,完成数据采集和数据处理) 包结构目录如下图所示: 主要代码: (sfw.py) # -*- …...
ReactPress—基于React的免费开源博客CMS内容管理系统
ReactPress Github项目地址:https://github.com/fecommunity/reactpress 欢迎提出宝贵的建议,感谢Star。 {int sum 0;…...
期权交易策略 v0.1
一.概述 1.参考 <期权波动率与定价> 2.期权价格 标的现价100元,到期日价格可能情况如下。 价格 80 90 100 110 120 概率 20% 20% 20% 20% 20% 持有标的时,期望收益为0.如果持有100的看涨期权,忽略期权费,期望收益为(100-100)*0.2…...
pytorch学习:矩阵分解:奇异值分解(SVD分解)
前言 矩阵分解(Matrix Decomposition)是将一个矩阵分解成多个矩阵的乘积的过程,这种分解方法在计算、机器学习和线性代数中有广泛应用。不同的分解方式可以简化计算、揭示矩阵的内在结构或提高算法的效率。 奇异值分解 奇异值分解…...
接口测试用例设计的关键步骤与技巧解析!
简介 接口测试在需求分析完成之后,即可设计对应的接口测试用例,然后根据用例进行接口测试。接口测试用例的设计也需要用到黑盒测试用例设计方法,和测试流程与理论章节的功能测试用例设计的方法类似,设计过程中还需要增加与接口特…...
CSS画icon图标系列(一)
目录 前言: 一、向右箭头 1.原理: 2.代码实现 3.结果展示: 二、钟表 1.原理: 2.代码展示: 3.最终效果: 三、小手机 1.原理: 2.代码展示: 3.最后效果: 四、结…...
【数据结构-合法括号字符串】【华为笔试题】力扣1190. 反转每对括号间的子串
给出一个字符串 s(仅含有小写英文字母和括号)。 请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。 注意,您的结果中 不应 包含任何括号。 示例 1: 输入:s “…...
qt QFileInfo详解
1、概述 QFileInfo是Qt框架中用于获取文件信息的工具类。它提供了与操作系统无关的文件属性,如文件的名称、位置(路径)、访问权限、类型(是否为目录或符号链接)等。此外,QFileInfo还可以获取文件的大小、创…...
金华迪加 现场大屏互动系统 mobile.do.php 任意文件上传漏洞复现
0x01 产品简介 金华迪加现场大屏互动系统是一种集成了先进技术和创意设计的互动展示解决方案,旨在通过大屏幕和多种交互方式,为观众提供沉浸式的互动体验。该系统广泛应用于各类活动、展览、会议等场合,能够显著提升现场氛围和参与者的体验感。 0x02 漏洞概述 金华迪加 现…...
探寻5G工业网关市场,5G工业网关品牌解析
随着5G技术的浪潮席卷全球,工业领域正经历着一场前所未有的变革。5G工业网关,作为连接工业设备与云端的桥梁,以其高速、低延迟的数据传输能力和强大的边缘计算能力,成为推动工业数字化转型的关键力量。那么,在众多5G工…...
RK3568开发板静态IP地址配置
1. 连接SSH MYD-LR3568 开发板设置了静态 eth0:1 192.168.0.10 和 eth1:1 192.168.1.10,在没有串口时调试开发板,可以用工具 SSH 登陆到开发板。 首先需要用一根网线直连电脑和开发板,或者通过路由器连接到开发板,将电脑 IP 手动设…...
element-plus table tableRowClassName 无效
官网上给的是 .el-table .warning-row {--el-table-tr-bg-color: var(--el-color-warning-light-9); } .el-table .success-row {--el-table-tr-bg-color: var(--el-color-success-light-9); } 但是 如果 加上了 scoped 这样样式是无效的 在 vue3 中用样式穿透 即可生…...
商务英语学习柯桥学外语到泓畅-老外说“go easy on me”是什么意思?
在口语中“go easy on sb ”这个短语是很常见的 01 go easy on me 怎么理解? 在口语中,“go easy on me”是一个非常常见的表达,通常表示请求对方在某方面对自己宽容一些,不要对自己太过苛刻或严厉。 短语(goÿ…...
【Python爬虫基础】基于 Python 的反爬虫机制详解与代码实现
基于 Python 的反爬虫机制详解与代码实现 在如今的信息时代,数据的重要性不言而喻。许多企业网站都包含着宝贵的数据,这些数据可能会被网络爬虫恶意抓取,这种行为不仅影响服务器的正常运行,还可能泄露商业机密。为了应对这种情况,网站开发人员需要了解并应用有效的反爬虫…...
HTB:PermX[WriteUP]
目录 连接至HTB服务器并启动靶机 1.How many TCP ports are listening on PermX? 使用nmap对靶机TCP端口进行开放扫描 2.What is the default domain name used by the web server on the box? 使用curl访问靶机80端口 3.On what subdomain of permx.htb is there an o…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
