单例模式(饿汉模式 懒汉模式)与一些特殊类设计
文章目录
一、不能被拷贝的类
二、只能在堆上创建类对象
三、只能在栈上创建类对象
四、不能被继承的类
五、单例模式
5、1 什么是单例模式
5、2 什么是设计模式
5、3 单例模式的实现
5、3、1 饿汉模式
5、3、1 懒汉模式
🙋♂️ 作者:@Ggggggtm 🙋♂️
👀 专栏:C++ 👀
💥 标题:特殊类的设计💥
❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️
一、不能被拷贝的类
一个类拷贝都是由拷贝构造来完成的。拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。代码如下:
class NonCopyableClass { public:NonCopyableClass() {}private:// 禁用拷贝构造函数NonCopyableClass(const NonCopyableClass&) = delete;// 禁用拷贝赋值运算符NonCopyableClass& operator=(const NonCopyableClass&) = delete; };int main() {NonCopyableClass obj1;// 编译错误,不能拷贝对象// NonCopyableClass obj2(obj1);//NonCopyableClass obj3 = obj1;return 0;在C++98中,将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有也是可以的。
二、只能在堆上创建类对象
我们在栈和静态区创建对象时,都需要调用构造函数来初始化。同时,为了防止拷贝和赋值在栈空间上,所以将默认构造、拷贝构造、赋值重载都禁用了。
那我们可以在类内部单独提供一个动态申请对象的静态成员函数。具体代码如下:
class HeapOnly { public:// 提供一个公有的,获取对象的方式,对象控制是new出来的static HeapOnly* CreateObj(){return new HeapOnly;}// 防拷贝HeapOnly(const HeapOnly& hp) = delete;HeapOnly& operator=(const HeapOnly& hp) = delete;void Destroy() {delete this;} private:// 构造函数私有HeapOnly():_a(0){} private:int _a; };int main() {HeapOnly* hp = HeapOnly::CreateObj();//HeapOnly copy(*hp);hp->Destroy();return 0; }
三、只能在栈上创建类对象
为了防止在堆上或者静态区申请对象,构造函数应该私有。可以在类内部提供一个返回栈对象的方法。代码如下:
class StackOnly { public:static StackOnly CreateObj(){StackOnly st;return st;}private:// 构造函数私有StackOnly():_a(0){} private:int _a; };但是,此时还能拷贝构造和赋值呢!!!那么能够禁用掉拷贝构造吗?答案是不能的。原因是我们通过传值返回的栈对象,此时必须需要拷贝。不能够传引用返回,因为是局部变量。出了函数就会被销毁。我们最多的就是禁用掉new的使用,具体代码如下:
class StackOnly { public:static StackOnly CreateObj(){StackOnly st;return st;}// 不能防拷贝//StackOnly(const StackOnly& st) = delete;StackOnly& operator=(const StackOnly& st) = delete;void* operator new(size_t n) = delete; private:// 构造函数私有StackOnly():_a(0){} private:int _a; };int main() {StackOnly st1 = StackOnly::CreateObj();// 拷贝构造static StackOnly copy2(st1);//StackOnly* copy3 = new StackOnly(st1);return 0; }
四、不能被继承的类
一个类不能被继承有两种方法:
- C++98方式:构造函数私有化,派生类中调不到基类的构造函数。则无法继承。
class NonInherit { public:static NonInherit GetInstance(){return NonInherit();} private:NonInherit(){} };- C++11方法:final关键字,final修饰类,表示该类不能被继承。
class A final {// .... };
五、单例模式
5、1 什么是单例模式
单例模式是一种设计模式,用于确保在整个应用程序中只存在一个特定类的实例对象,该实例对象被所有程序模块共享。其主要目的是限制类的实例化操作,以确保在任何情况下都只能获得同一个实例。
比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
5、2 什么是设计模式
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
5、3 单例模式的实现
单例模式实现的方法有两种:饿汉模式、懒汉模式。我们先来看一下饿汉模式的实现。
5、3、1 饿汉模式
所谓饿汉模式,就是在main函数之前,就会创建出对象。并不会考虑到你是否要用这个对象。那怎么实现呢?
首先,为了保证只能实例出一份对象,就必须把构造函数私有化。其次,需要在自己的类内部定义一个静态的类对象或者类指针。然后在类内部定义一些静态成员函数来初始化、获取对象/指针等操作。具体代码如下:
//class MemoryPool //{ //public: // //private: // // 构造函数私有化 // MemoryPool() // {} // // char* _ptr = nullptr; // // ... // // static MemoryPool _inst; // 声明 //}; //定义 //MemoryPool MemoryPool::_inst;class MemoryPool { public:static MemoryPool* GetInstance(){return _pinst;}void* Alloc(size_t n){void* ptr = nullptr;// ....return ptr;}void Dealloc(void* ptr){// ...}MemoryPool(MemoryPool& my) = delete;MemoryPool& operator= (MemoryPool& my) = delete; private:// 构造函数私有化MemoryPool(){}char* _ptr = nullptr;// ...static MemoryPool* _pinst; // 声明 };// 定义 MemoryPool* MemoryPool::_pinst = new MemoryPool;int main() {//MemoryPool pool1;//MemoryPool pool2;void* ptr1 = MemoryPool::GetInstance()->Alloc(10);MemoryPool::GetInstance()->Dealloc(ptr1); }我们来分析一下:当类内定义的是静态成员时,需要在类外进行初始化。那么在类外能够调用私有的构造函数进行初始化吗?答案是可以的!因为该成员是属于类内部的私有成员,只不过是在类外进行的初始化。
那么能在类内定义非静态类对象吗?答案是不可以的,这本身就是语法错误。其次静态成员变量并不属于某个对象,而是属于整个类。
总结饿汉模式(Eager Initialization) 的优点:
- 实现简单,线程安全。在类加载时就创建了实例,没有线程安全问题。
- 可以保证在任何时候获取到同一个实例。
缺点:
- 类加载时即创建实例,尤其是在实例初始化比较耗时的情况下,会影响到程序的启动速度。
- 如果该实例一直没有被使用,则会造成内存的浪费。
- 当有多个单例对象时,饿汉模式无法很好的控制其初始化先后顺序。当然,在一个文件內部还好,在多个文件中就无法确定静态成员的初始化顺序。
5、3、1 懒汉模式
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
懒汉模式在第一次使用时才会创建单例对象,延迟实例化以节省资源。代码如下:class MemoryPool { public:static MemoryPool* GetInstance(){if (_pinst == nullptr){_pinst = new MemoryPool;}return _pinst;}void* Alloc(size_t n){void* ptr = nullptr;// ....return ptr;}void Dealloc(void* ptr){// ...}// 实现一个内嵌垃圾回收类 class CGarbo {public:~CGarbo(){if (_pinst)delete _pinst;}};MemoryPool(MemoryPool& my) = delete;MemoryPool& operator= (MemoryPool& my) = delete; private:// 构造函数私有化MemoryPool(){// ....}char* _ptr = nullptr;// ...static MemoryPool* _pinst; // 声明 };// 定义 MemoryPool* MemoryPool::_pinst = nullptr;// 回收对象,main函数结束后,他会调用析构函数,就会释放单例对象 static MemoryPool::CGarbo gc;总结懒汉模式(Lazy Initialization) 优点:
- 延迟实例化,只有第一次调用获取实例的方法时才会创建对象,避免了资源浪费。
- 可以控制对象的初始化顺序。
- 不影响程序的启动速度。
缺点:
- 不是线程安全的,如果多个线程并发地调用获取实例的方法,可能会创建多个实例。
- 在多线程环境下,需要额外的同步措施来保证线程安全,增加了复杂性开销。
相关文章:
单例模式(饿汉模式 懒汉模式)与一些特殊类设计
文章目录 一、不能被拷贝的类 二、只能在堆上创建类对象 三、只能在栈上创建类对象 四、不能被继承的类 五、单例模式 5、1 什么是单例模式 5、2 什么是设计模式 5、3 单例模式的实现 5、3、1 饿汉模式 5、3、1 懒汉模式 🙋♂️ 作者:Ggggggtm &#x…...
133. 克隆图
133. 克隆图 题目-中等难度示例1. bfs 题目-中等难度 给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。 图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。…...
交流耐压试验目的
试验目的 交流耐压试验是鉴定电力设备绝缘强度最有效和最直接的方法。 电力设备在运行中, 绝缘长期受着电场、 温度和机械振动的作用会逐渐发生劣化, 其中包括整体劣化和部分劣化,形成缺陷, 例如由于局部地方电场比较集中或者局部…...
使用 YCSB 和 PE 进行 HBase 性能压力测试
HBase主要性能压力测试有两个,一个是 HBase 自带的 PE,另一个是 YCSB,先简单说一个两者的区别。PE 是 HBase 自带的工具,开箱即用,使用起来非常简单,但是 PE 只能按单个线程统计压测结果,不能汇…...
正则表达式相关概念及不可见高度页面的获取
12.正则 概念:匹配有规律的字符串,匹配上则正确 1.正则的创建方式 构造函数创建 // 修饰符 igm// i 忽视 ignore// g global 全球 全局// m 换行 var regnew RegExp("匹配的内容","修饰符")var str "this is a Box";var reg new RegExp(&qu…...
深入学习 Redis - 分布式锁底层实现原理,以及实际应用
目录 一、Redis 分布式锁 1.1、什么是分布式锁 1.2、分布式锁的基础实现 1.2.1、引入场景 1.2.2、基础实现思想 1.2.3、引入 setnx 1.3、引入过期时间 1.4、引入校验 id 1.5、引入 lua 脚本 1.5.1、引入 lua 脚本的原因 1.5.2、lua 脚本介绍 1.6、过期时间续约问题&…...
Hive行转列[一行拆分成多行/一列拆分成多列]
场景: hive有张表armmttxn_tmp,其中有一个字段lot_number,该字段以逗号分隔开多个值,每个值又以冒号来分割料号和数量,如:A3220089:-40,A3220090:-40,A3220091:-40,A3220083:-40,A3220087:-40,A3220086:-4…...
TypeScript系列之类型 string
文章の目录 背景写在最后 背景 与JavaScript不同的是,TypeScript使用的是静态类型,比如说它指定了变量可以保存的数据类型。如下面代码所示,如果在JavaScript中,指定变量可以保存的数据类型,会报错:类型注…...
【C++】动态内存管理 ③ ( C++ 对象的动态创建和释放 | new 运算符 为类对象 分配内存 | delete 运算符 释放对象内存 )
文章目录 一、C 对象的动态创建和释放1、C 语言 对象的动态创建和释放 的方式2、C 语言 对象的动态创建和释放 的方式 二、代码示例 - 对象的动态创建和释放 一、C 对象的动态创建和释放 使用 C 语言中的 malloc 函数 可以为 类对象 分配内存 ; 使用 free 函数可以释放上述分配…...
AMS爆炸来袭,上线即巅峰
1.关于首发项目Antmons(AMS)空投结果 Gate.io Startup 首发项目Antmons代币AMS于Aug15th,AM 07:00开始下单,24小时内下单同等对待总共有15,950人下单,下单总价值超过1,000万美金分发系数约为0.001640495298341。根据上线规则AMS项目认购成功,…...
是面试官放水,还是公司实在是太缺人?这都没挂,华为原来这么容易进...
华为是大企业,是不是很难进去啊?” “在华为做软件测试,能得到很好的发展吗? 一进去就有9.5K,其实也没有想的那么难” 直到现在,心情都还是无比激动! 本人211非科班,之前在字节和腾…...
怒刷LeetCode的第2天(Java版)
目录 第一题 题目来源 题目内容 解决方法 方法一:滑动窗口 方法二:双指针加哈希表 第二题 题目来源 题目内容 解决方法 方法一:二分查找 方法二:归并排序 方法三:分治法 第三题 题目来源 题目内容 解…...
AUTOSAR汽车电子嵌入式编程精讲300篇-车载CAN总线网络的异常检测(续)
目录 车载 CAN 总线网络异常检测技术 3.1 车载 CAN 总线网络异常检测技术概述 3.1.1基于统计的异...
mojo安装
docker安装mojo 官网 https://developer.modular.com/login 很奇怪登录页面不显示 类似于网站劫持 docker 安装mojo带jupyterlab的方式 https://hub.docker.com/r/lmq886/mojojupyterlab 拉取镜像 docker pull lmq886/mojojupyterlab docker pull lmq886/mojojupyterlab:1.2 启…...
【探索Linux】—— 强大的命令行工具 P.8(进程地址空间)
阅读导航 前言一、内存空间分布二、什么是进程地址空间1. 概念2. 进程地址空间的组成 三、进程地址空间的设计原理1. 基本原理2. 虚拟地址空间 概念 大小和范围 作用 虚拟地址空间的优点 3. 页表 四、为什么要有地址空间五、总结温馨提示 前言 前面我们讲了C语言的基础知识&am…...
vue3 - Element Plus 切换主题色及el-button hover颜色不生效的解决方法
GitHub Demo 地址 在线预览 Element Plus 自定义主题官方文档 如果您想要通过 js 控制 css 变量,可以这样做: // document.documentElement 是全局变量时 const el document.documentElement // const el document.getElementById(xxx)// 获取 css 变…...
【C++面向对象侯捷】1.C++编程简介
文章目录 视频来源:我的百度网盘...
年龄大了转嵌入式有机会吗?
年龄大了转嵌入式有机会吗? 首先,说下结论:年龄并不是限制转行嵌入式软件开发的因素,只要具备一定的编程和电子基础知识,认真学习和实践,是可以成为优秀的嵌入式软件开发工程师的。最近很多小伙伴找我&…...
Mysql高级——索引优化和查询优化(2)
5. 排序优化 5.1 排序优化 问题:在 WHERE 条件字段上加索引,但是为什么在 ORDER BY 字段上还要加索引呢? 优化建议: SQL 中,可以在 WHERE 子句和 ORDER BY 子句中使用索引,目的是在 WHERE 子句中避免全表…...
SpringMVC的拦截器和JSR303的使用
目录 一、JSR303 二、拦截器(interceptor) 一、JSR303 1.1.什么是JSR303 JSR 303,它是Java EE(现在称为Jakarta EE)规范中的一部分。JSR 303定义了一种用于验证Java对象的标准规范,也称为Bean验证。 Bean验…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
