yo!这里是单例模式相关介绍
目录
前言
特殊类设计
只能在堆上创建对象的类
1.方法一(构造函数下手)
2.方法二(析构函数下手)
只能在栈上创建对象的类
单例模式
饿汉模式实现
懒汉模式实现
后记
前言
在面向找工作学习c++的过程中,除了基本的语法知识以外,还有一些被反复使用、经验总结的设计模式或者说设计思想值得大家学习,也可以说是面试当中面试官大概率问到的面试题。在本节中,除了介绍标题所述的单例模式,还要了解一些特殊类的设计思想,当然也需要引入这些思想才能更好的理解单例模式。对于常见的特殊类的设计,比如不能被拷贝的类(将拷贝构造函数和赋值运算符重载设置为删除函数)、不能被继承的类(在类名后面加上final关键字)等这些都是一些较为简单的特殊类设计,难一点的像只能在堆或者栈上创建的类、只能创建一个对象的类(单例模式)这些又如何实现?往下看!
特殊类设计
-
只能在堆上创建对象的类
1.方法一(构造函数下手)
从构造函数下手,也就是把构造函数私有化,这样我们就可以控制谁能去使用构造函数了,控制的方法就是定义一个共有的接口,在该接口内使用允许的方法创建对象。这里就是创建了一个静态成员函数——getObj(),在接口内去new一个对象返回出去,为什么是静态呢?因为普通成员函数无法在类外使用,必须创建出对象才能使用,这就会产生“先有鸡还是先有蛋”的问题。
此外,将拷贝构造函数和赋值运算符重载设置为删除函数,是为了防拷贝,因为拷贝与赋值可以在栈上或静态区创建对象,参考代码如下。
代码:
class HeapOnly
{
public:static HeapOnly* getObj(int a){return new HeapOnly(a);}private:HeapOnly(int a):_a(a){}HeapOnly(const HeapOnly& hp) = delete;HeapOnly& operator=(const HeapOnly& hp) = delete;private:int _a = 0;
};
调试:

2.方法二(析构函数下手)
除了将构造函数私有化,也可以将析构函数私有化,思想是一样的,即将析构函数私有化,之后定义一个共有的接口去使用允许的方式释放对象,如下代码块的delObj函数,那为什么不需要设置成静态函数呢?因为此时对象已经创建出来了,直接调用此函数来释放资源即可,其他方式创建出来的对象会因为没有析构函数而编译不通过。
值得提一嘴的是,我们可以不用传入指向资源的指针到delObj函数内,因为普通成员函数有一个参数就是当前对象的指针,直接去释放即可。
代码:
class HeapOnly
{
public:void delObj(HeapOnly* pho){delete pho;}/*void delObj(){delete this;}*/
private:~HeapOnly(){}
private:int _a = 0;
};
调试:

-
只能在栈上创建对象的类
只能在栈上创建对象,这种就不能够在析构函数上下手了,考虑一下构造函数,思想其实与只能在堆上创建对象一样——设置共有的静态接口,在接口内定义对象返回出去,但其实这样的做法是不能做到严格把控的,也就是说写不出来只能在栈上创建对象的类,下面解释。
我们先按之前的思想将其写出来,如下代码块。图一可以看到,的确只能在栈上创建对象,但是看图二,可以通过static将对象拷贝一份在静态区,这就是存在的bug。有人说将拷贝函数和赋值函数都设置为delete函数,但是这样就无法将getObj函数内定义的对象返回出来了,大家可以尝试一下,有解决的方法可以写在评论区,一块讨论。
代码:
class StackOnly
{
public:static StackOnly getObj(int a){return StackOnly(a);}private:StackOnly(int a = 0):_a(a){}public:int _a = 0;
};
单例模式
一个类只能创建一个对象,即单例模式。单例模式是一种创建对象的设计模式,它确保一个类只有一个实例,并提供全局访问该实例的方式。
在单例模式中,类的构造函数被私有化,使得外部无法直接创建对象。类内部维护一个静态变量来保存唯一的实例,通过一个公共的静态方法来获取该实例。当第一次调用该方法时,会创建一个对象并赋值给静态变量,以后的调用都直接返回这个静态变量。
单例模式常用于需要限制全局资源访问的场景,比如数据库连接、线程池等。通过单例模式,可以确保全局只有一个实例存在,并提供一种方便的方式来访问该实例。有两个实现方式来实现单例模式:饿汉模式和懒汉模式。
-
饿汉模式实现
饿汉模式:不管你将来用不用,程序启动时就创建一个唯一的实例对象,也就是一开始(在main函数之前)就创建对象。
优点:较简单,不存在线程安全问题
缺点:因为在main函数之前,所以可能会导致进程启动慢,而且如果有多个单例类对象实例启动顺序不确定
实现原理:
首先,因为是单例模式,只能创建一个对象,所以先将拷贝构造函数、赋值运算符重载函数设置为删除函数,以防止拷贝。其次,按照前面特殊类设计思想,我们依旧将构造函数私有化,并定义一个共有函数用来创建符合条件的对象,这里需要只能创建一个对象,因此我们定义一个静态成员变量(可以是类指针,也可以是类对象),因为静态变量只有一份。静态成员变量是类内声明,类外初始化,因为是一开始就创建,所以在初始化时我们就new一个对象。然后,我们将定义一个共有的静态成员函数来获取这个变量即可,为什么这个成员函数也是静态的?因为普通成员函数内不能使用静态成员变量,代码参考如下:
代码:
class Singleton
{
public:static Singleton* getInstance(){return _inst;}
private:Singleton(){}Singleton(const Singleton& x) = delete;Singleton& operator=(const Singleton& x) = delete;static Singleton* _inst;
};
Singleton* Singleton::_inst = new Singleton();
-
懒汉模式实现
当单例对象构造十分耗时或者占用很多资源,比如加载插件、初始化网络连接、读取文件等,而且有可能该对象程序运行时不会用到,那么在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。
懒汉模式:在第一次使用时才创建单例对象
优点:进程启动无负载,多个单例实例启动顺序可以自由控制
缺点:复杂、存在线程安全问题
实现原理:
如下代码块,懒汉模式实现过程与饿汉模式实现的大致框架都是一样的,主要在于因为懒汉模式是第一次使用时再创建这个对象,因此静态成员变量在初始化时设置为空。先看非线程安全版本的getInstance函数,如果静态成员变量_inst为空,说明还没创建,此时应该去创建这个对象,如果非空,说明已经创建过了,直接返回这个变量出去。
其次,考虑到多个线程同时竞争创建这个实例,同时判断_inst为空,同时创建出了多个对象,导致线程安全问题,所以我们需要加锁保护,定义并初始化一把静态锁,在判断_inst是否为空之前加锁保护,这样就能保证进入判断的线程只有一个,其他线程都得挂起等待。
但是发现在加锁的外面又加了一层判空的if语句,这是因为只需要第一次进来时需要用到锁,第二次往后进来都是只需要返回这个指针即可,否则每次进入这个函数都需要申请锁,会降低效率,这种方式叫做Double-Cheack,适用于第一次加锁后续不需要的情形。
以上是懒汉模式的实现过程,下面再考虑一个问题——单例对象释放问题,首先一般情况下,单例对象是不需要释放的,因为一整个程序都可能需要用到它,单例对象在进程正常结束后也会自动释放;其次,有些场景需要释放,比如单例对象释放时,需要进行持久化操作(将数据信息保存在文件中),那么此时一个释放的方法就是可以通过内部类的方式实现单例对象释放机制。如下面代码块实现的DelInstance类,在成员中定义这样类型的静态对象,当程序结束时,系统会自动调用其析构函数从而释放单例对象,而所谓的持久化操作就可以在其析构函数内做。
代码:
class Singleton
{
public://非线程安全版本/*static Singleton* getInstance(){if (_inst == nullptr){_inst = new Singleton();}return _inst;}*/static Singleton* getInstance(){if(_inst==nullptr){lock_guard<mutex> lg(_mtx);if (_inst == nullptr){_inst = new Singleton();}}return _inst;}class DelInstance{public://持久化操作~DelInstance(){if (_inst)delete _inst;}};static DelInstance _delins;
private:Singleton(){}Singleton(const Singleton& x) = delete;Singleton& operator=(const Singleton& x) = delete;static Singleton* _inst;static mutex _mtx;
};
Singleton* Singleton::_inst = nullptr;
mutex Singleton::_mtx; //注意:即使不需要初始化,静态成员变量也需要写在这
后记
通过实现只能在堆或栈上创建对象的类,学习到如何实现单例模式,这是一种设计模式,是大多数程序员共同发现的“套路”,套用相同的模式可以让代码可读性更强、更容易被他人理解、使代码编写更加工程化。实现单例模式也是分为两种方法,其中更加建议使用懒汉模式。不仅仅是学会本文中特殊类设计的方法,更要注重设计的思想,对于面试中面对考官出的其他类的实现题目提供了一种思考或解决办法,好了,以上类的设计自己尝试实现一把,有问题举手。
相关文章:
yo!这里是单例模式相关介绍
目录 前言 特殊类设计 只能在堆上创建对象的类 1.方法一(构造函数下手) 2.方法二(析构函数下手) 只能在栈上创建对象的类 单例模式 饿汉模式实现 懒汉模式实现 后记 前言 在面向找工作学习c的过程中,除了基本…...
2023年上-未来几年我要做什么
1月份,离职。 2月份,春节休假回来,中旬去参加了一个月的瑜伽培训,学会了倒立、鹤蝉。。。。 3月份,瑜伽培训结束,开始收拾房子,并调研各类项目。 4月份,参与了朋友的区块链项目 …...
智能汽车竞赛摄像头处理(3)——动态阈值二值化(大津法)
前言 (1)在上一节中,我们学习了对图像的固定二值化处理,可以将原始图像处理成二值化的黑白图像,这里面的本质就是将原来的二维数组进行了处理,处理后的二维数组里的元素都是0和255两个值。 (2…...
BGP协议
1.BGP相关概念 1.1 BGP的起源 不同自治系统(路由域)间路由交换与管理的需求推动了EGP的发展,但是EGP的算法简单,无法选路,从而被BGP取代。 自治系统:(AS) IGP:自治系统…...
一个完整工作流管理系统的组成部分
一个完整工作流管理系统的组成部分 一个完整的工作流管理系统通常由工作流引擎、工作流设计器、流程操作、工作流客户端程序、流程监控、表单设计器、与表单的集成以及与应用程序的集成八个部分组成。 一、工作流组成 1. 工作流引擎 工作流引擎作为工作流管理系统的核心部分&…...
鱼和熊掌如何兼得?一文解析RDS数据库存储架构升级
在2023年云栖大会上,阿里云数据库产品事业部负责人李飞飞在主题演讲中提到,瑶池数据库推出“DB存储”一体化能力,结合人工智能、机器学习、存储等方法和创新能力,实现Buffer Pool Extension能力和智能冷温热数据分层能力。在大会的…...
中科大计网学习记录笔记(五):协议层次和服务模型
前言: 学习视频:中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》课程 该视频是B站非常著名的计网学习视频,但相信很多朋友和我一样在听完前面的部分发现信…...
同构异机迁移方案2_目标服务器仅安装数据库软件scp物理文件
源端和目标端的数据库版本需要保持一致,补丁版本可以不一致,目标端磁盘空间不能小于源端空间,目标端只需要安装 Oracle 软件即可。 特别说明:本文档案例Oracle的安装路径不同,数据目录一致,采用scp的方式实…...
华为机考入门python3--(6)牛客6-质数因子
分类:质数、素数 知识点: 取余符号% 5%3 2 取整符号// 5//3 1 list中int元素转str map(str, list) 题目来自【牛客】 def prime_factors(n): """ 输入一个正整数n,输出它的所有质因子(重复的也…...
11月最新版付费进群源码自动定位+开源
Nginx 1.22.1 php5.6 mysql5.6 数据库配置:/config/database.php 配置后台域名:config/extra/ip.php 设置伪静态thinkphp 后台账号88886666 密码12345 代码结构 关键代码剖析 <?php // ----------------------------------------------------…...
Python算法题集_旋转图像
Python算法题集_旋转图像 题目48:旋转图像1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【矩阵复本】2) 改进版一【矩阵转置矩阵反转】3) 改进版二【四值旋转】 4. 最优算法 题目48:旋转图像 本文为Python算法题集之一…...
[ChatGPT们】ChatGPT 如何辅助编程初探
主页:元存储的博客 全文 9000 字, 原创请勿转载。 我没有写过诗,但有人说我的代码像诗一样优雅 -- 雷军 图片来源:https://www.bilibili.com/video/BV1zL411X7oS/ 1. 引言 作为一个程序员,我们不仅要熟悉各种编程语…...
深入Spring MVC的工作流程
深入Spring MVC的工作流程 在Spring MVC的面试问题中,常常被询问到的一个问题。Spring MVC的程序中,HTTP请求是如何从开始到结束被处理的。为了研究这个问题,我们将需要深入学习一下Spring MVC框架的核心过程和工作流程。 1. 启动请求生命周…...
我的数据结构c(给自己用的)
目录 顺序表: 链表: 栈: 队列: 我想在之后的大学数据结构课上需要自己写来做题,但每次都自己写,那太麻烦了,所以我就将这个博客来把所有的C语言的数据结构弄上去, 问我为什么不…...
使用Arcgis对欧洲雷达高分辨率降水数据重投影
当前需要使用欧洲高分辨雷达降水数据,但是这个数据的投影问题非常头疼。实际的投影应该长这样(https://gist.github.com/kmuehlbauer/645e42a53b30752230c08c20a9c964f9?permalink_comment_id2954366https://gist.github.com/kmuehlbauer/645e42a53b307…...
[Python] scikit-learn中数据集模块介绍和使用案例
sklearn.datasets模块介绍 在scikit-learn中,可以使用sklearn.datasets模块中的函数来构建数据集。这个模块提供了用于加载和生成数据集的函数。 API Reference — scikit-learn 1.4.0 documentation 以下是一些常用的sklearn.datasets模块中的函数 load_iris() …...
Qt-互斥量-临界区-QMutex-QMutexLocker-QReadWriteLock
文章目录 1.QMutex2.QMutexLocker3.QReadWriteLock 在Qt中,互斥量(Mutex)是用于同步多线程访问共享资源的一种机制。临界区(Critical Section)是指一段必须由单个线程执行的代码区域,防止多个线程同时执行这…...
《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述(6)
接前一篇文章:《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述(5) 4.1 PCIe总线的基础知识 与PCI总线不同,PCIe总线使用端到端的连接方式,在一条PCIe链路的两端只能各连接一个设备,这两个…...
uniapp 高德地图显示
1. uniapp 高德地图显示 使用前需到**高德开放平台(https://lbs.amap.com/)**创建应用并申请Key 登录 高德开放平台,进入“控制台”,如果没有注册账号请先根据页面提示注册账号 打开 “应用管理” -> “我的应用”页面…...
2024年最新幻兽帕鲁服务器搭建教程
玩转幻兽帕鲁服务器,阿里云推出新手0基础一键部署幻兽帕鲁服务器教程,傻瓜式一键部署,3分钟即可成功创建一台Palworld专属服务器,成本仅需26元,阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…...
seo关键词查询如何结合竞争对手分析
SEO关键词查询如何结合竞争对手分析 在当今数字营销的激烈竞争中,SEO(搜索引擎优化)已经成为了提升网站流量和品牌知名度的关键手段。而在SEO的实践过程中,关键词查询和竞争对手分析往往被认为是最重要的两大环节。SEO关键词查询…...
北京交通大学校内邮箱配置指南:Windows与Mac系统自带邮件应用全攻略
1. 为什么需要配置校内邮箱? 作为北京交通大学的师生,校内邮箱是重要的通讯工具。无论是接收学校通知、提交作业,还是与导师同学沟通,都需要用到这个官方邮箱。很多同学第一次使用时,可能会被各种服务器设置搞得一头雾…...
告别重复造轮子:用快马AI一键生成智能车数据处理与可视化工具
今天想和大家分享一个提升智能车开发效率的小工具。在智能车项目中,我们经常需要处理大量传感器数据,比如IMU、GPS等设备采集的CSV文件。传统做法是每次都要从头写数据处理代码,既浪费时间又容易出错。最近我发现用InsCode(快马)平台可以快速…...
3个效率倍增步骤:茉莉花插件让中文文献管理效率提升92%
3个效率倍增步骤:茉莉花插件让中文文献管理效率提升92% 【免费下载链接】jasminum A Zotero add-on to retrive CNKI meta data. 一个简单的Zotero 插件,用于识别中文元数据 项目地址: https://gitcode.com/gh_mirrors/ja/jasminum 茉莉花插件是专…...
Flowable流程可视化实战:手把手教你自定义高亮流程图(Java AWT绘图详解)
Flowable流程可视化实战:深度定制高亮流程图的技术解析 在业务流程管理(BPM)系统中,流程可视化是提升用户体验的关键环节。本文将深入探讨如何基于Flowable工作流引擎,通过Java AWT绘图技术实现高度定制化的流程图渲染…...
Windows下GridSearchCV并行计算避坑指南:解决n_jobs=-1导致的编码错误
Windows平台高效调参实战:GridSearchCV并行计算编码问题终极解决方案 当你在Windows系统上使用Scikit-learn的GridSearchCV进行超参数调优时,是否遇到过这样的报错信息?"UnicodeEncodeError: ascii codec cant encode characters...&quo…...
如何基于SecGPT构建企业级安全智能助手:完整实践指南
如何基于SecGPT构建企业级安全智能助手:完整实践指南 【免费下载链接】SecGPT SecGPT网络安全大模型 项目地址: https://gitcode.com/gh_mirrors/se/SecGPT SecGPT作为一款专业的网络安全大模型,为企业构建智能化安全防护体系提供了强大支持。本文…...
从特征多项式到行列式:揭秘矩阵特征值之积的几何意义
1. 特征多项式:打开矩阵奥秘的钥匙 我第一次接触特征多项式时,完全被这个抽象的概念搞晕了。直到有一天,我的导师用了一个简单的比喻:"特征多项式就像是矩阵的DNA检测报告,它能告诉我们这个矩阵最本质的特性。&qu…...
C++的std--ranges算法任务
C20引入的std::ranges算法彻底改变了标准库操作数据的方式,为现代C开发者提供了更简洁、更安全的范围处理工具。传统算法需要传递首尾迭代器,容易引发越界错误,而ranges通过直接操作范围视图和容器,大幅提升了代码可读性和安全性。…...
OpCore-Simplify:让黑苹果配置从3天缩短到15分钟的智能助手
OpCore-Simplify:让黑苹果配置从3天缩短到15分钟的智能助手 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 你是否曾因为复杂的黑苹果配置…...

