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年新版基于阿里云搭建幻兽帕鲁服…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...

【阅读笔记】MemOS: 大语言模型内存增强生成操作系统
核心速览 研究背景 研究问题:这篇文章要解决的问题是当前大型语言模型(LLMs)在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色,但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成(RA…...

基于Python的气象数据分析及可视化研究
目录 一.🦁前言二.🦁开源代码与组件使用情况说明三.🦁核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.🦁演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...

开疆智能Ethernet/IP转Modbus网关连接鸣志步进电机驱动器配置案例
在工业自动化控制系统中,常常会遇到不同品牌和通信协议的设备需要协同工作的情况。本案例中,客户现场采用了 罗克韦尔PLC,但需要控制的变频器仅支持 ModbusRTU 协议。为了实现PLC 对变频器的有效控制与监控,引入了开疆智能Etherne…...

【笔记】结合 Conda任意创建和配置不同 Python 版本的双轨隔离的 Poetry 虚拟环境
如何结合 Conda 任意创建和配置不同 Python 版本的双轨隔离的Poetry 虚拟环境? 在 Python 开发中,为不同项目配置独立且适配的虚拟环境至关重要。结合 Conda 和 Poetry 工具,能高效创建不同 Python 版本的 Poetry 虚拟环境,接下来…...