23种经典设计模式:单例模式篇(C++)
前言:
博主将从此篇单例模式开始逐一分享23种经典设计模式,并结合C++为大家展示实际应用。内容将持续更新,希望大家持续关注与支持。
什么是单例模式?
单例模式是设计模式的一种(属于创建型模式 (Creational Patterns) ),它确保某个类只有一个实例,并为该实例提供一个全局访问点。它常用于那些在整个系统中只需要一个实例的类,例如配置管理、日志记录、线程池、缓存等。

为什么选择单例模式?
1. 确保唯一性
有些时候,我们需要确保某个对象在整个系统中只存在一个。这样可以避免因为多次实例化导致的资源浪费或不一致性。
2. 节省资源
如果一个对象初始化需要大量资源,例如读取配置文件或建立数据库连接,那么多次实例化就可能导致不必要的开销。
3. 提供全局访问点
这让其他对象可以轻松地访问到该实例,并与之交互。
4. 单例模式的不足:
万事万物都没有绝对的好,不然也不会有23种设计模式,过度依赖单例模式可能使代码变得紧耦合和难以测试。因此,当考虑使用单例模式时,应当仔细权衡其优点和潜在的问题。
单例模式的分类?

单例模式的具体实现?
1. 饿汉式
- 特点:在类加载时就完成了初始化,静态成员对象的创建是在类加载时完成的。
- 优点:线程安全(基于类加载机制,避免了多线程同步问题)。
- 缺点:不是懒加载,可能造成资源浪费。
class Singleton {
private:// Singleton的私有静态实例static Singleton instance;// 私有构造函数确保只能通过getInstance方法来访问Singleton实例Singleton() {}public:// 公共静态方法,用于获取Singleton实例static Singleton& getInstance() {return instance;}
};// 初始化静态的Singleton实例
Singleton Singleton::instance;
2. 懒汉式
- 特点:在第一次调用时实例化。
- 优点:懒加载,只有在真正需要对象时才会创建。
- 缺点:需要处理线程安全问题。
class Singleton {
private:// Singleton的私有静态指针实例static Singleton* instance;// 私有构造函数确保只能通过getInstance方法来访问Singleton实例Singleton() {}public:// 公共静态方法,用于获取Singleton实例。如果实例不存在,就创建一个。static Singleton* getInstance() {if (!instance) { // 判断instance是否为空instance = new Singleton(); // 如果为空,则新建一个Singleton对象}return instance; // 返回Singleton对象的指针}
};// 初始化静态的Singleton指针实例为nullptr
Singleton* Singleton::instance = nullptr;
3. 懒汉式(带锁)
- 特点:在首次请求对象时创建实例,但加入了互斥锁以确保线程安全。
- 优势:懒加载,线程安全。
- 劣势:每次访问时都需要加锁,可能会有性能开销。
class Singleton {
private:static Singleton* instance;static std::mutex mtx; // 用于同步的互斥锁Singleton() {}public:static Singleton* getInstance() {std::lock_guard<std::mutex> lock(mtx); // 直接锁定if (!instance) {instance = new Singleton();}return instance;}
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
4. 双重检查锁定(DCL, Double Checked Locking)
- 特点:结合了懒汉式和synchronized同步锁。
- 优点:懒加载,线程安全,且性能较高。
class Singleton {
private:// Singleton的私有静态指针实例static Singleton* instance;// 用于同步的互斥锁static std::mutex mtx;Singleton() {}public:// 这里使用了双重检查锁定来确保线程安全static Singleton* getInstance() {if (!instance) { // 第一次检查,不加锁std::lock_guard<std::mutex> lock(mtx); // 加锁if (!instance) { // 第二次检查,已加锁instance = new Singleton(); }}return instance; }
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
5. 静态局部变量(C++11)
利用C++11特性,局部静态变量已经是线程安全的,并且无需额外的锁或同步机制。
class Singleton {
public:// 公共静态方法,用于获取Singleton实例的引用。// 这里利用了局部静态变量的特性,该变量只会初始化一次,并且这个初始化过程在C++11及以上是线程安全的。static Singleton& getInstance() {static Singleton instance; // 局部静态变量return instance; // 返回这个局部静态变量的引用}private:// 私有构造函数确保只能通过getInstance方法来访问Singleton实例Singleton() {}
};
6. 使用std::once_flag和std::call_once(C++11及以上):
- 特点:确保某个代码块只被执行一次。
- 优势:线程安全,性能较好。
- 劣势:依赖于C++11及以上版本的特性。
class Singleton {
private:// Singleton的私有静态指针实例static Singleton* instance;static std::once_flag onceFlag;// 私有构造函数Singleton() {}public:// 删除拷贝构造函数和赋值操作符,确保不能拷贝Singleton(const Singleton& other) = delete;Singleton& operator=(const Singleton& other) = delete;// 公共静态方法,用于获取或创建Singleton实例static Singleton* getInstance() {std::call_once(onceFlag, []() {instance = new Singleton();});return instance;}
};// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::onceFlag;
开发中的选择?
在实际开发中,选择单例模式的具体实现通常取决于以下因素:
-
线程安全性需求:在多线程应用中,单例模式的实现必须是线程安全的。但如果你知道应用永远不会在多线程环境中运行,你可以选择一个不考虑线程安全的简单实现。
-
性能考虑:某些单例实现(例如每次访问时都加锁的懒汉式)可能会对性能产生负面影响。但在现代硬件上,这种影响通常可以忽略不计,除非你的代码在高频、高并发场景下运行。
-
C++版本:在C++11及更高版本中,局部静态变量的初始化是线程安全的,这使得某些单例实现变得更为简洁和可靠。
基于上述因素,以下是在实际开发中经常使用的单例模式实现:
-
局部静态变量(推荐,尤其是C++11及以上):
这种方法简洁、线程安全,并且无需额外的锁或同步机制。
-
双重检查锁定(DCL, Double Checked Locking): 这在C++11之前可能是线程安全的选择,但需要谨慎使用,因为在某些老的编译器和硬件上可能会出现问题。
-
使用
std::call_once和std::once_flag: 这是C++11及以上版本提供的线程安全方法,可以确保对象只初始化一次。 -
饿汉式: 在程序启动时就创建实例。这种方法简单并且线程安全,但可能会导致不必要的资源浪费,特别是当单例对象很大或初始化成本很高时。
-
懒汉式(带锁): 在首次请求时创建实例,并使用互斥锁确保线程安全。这种方式在性能敏感的场景中可能不是最佳选择。
结论:
单例模式有许多不同的实现,每种实现都有其适用的场景和优缺点。在实践中,选择哪种实现需要根据具体需求和上下文进行权衡。
本文侧重于介绍单例模式在C++中的使用方法,若读者有不同的的理解和看法,欢迎在评论区留言!
相关文章:
23种经典设计模式:单例模式篇(C++)
前言: 博主将从此篇单例模式开始逐一分享23种经典设计模式,并结合C为大家展示实际应用。内容将持续更新,希望大家持续关注与支持。 什么是单例模式? 单例模式是设计模式的一种(属于创建型模式 (Creational Pa…...
ros中对move_base的调用
move_base包中自带costmap2d, global planner 等功能 也可以直接调用其中make_plan进行路径规划 #include "geometry_msgs/PoseStamped.h" #includde "nav_msgs/GetPlan.h"void fillPathRequest(nav_msgs::GetPlan::Request &request, float start_x…...
Git从本地库撤销已经添加的文件或目录
场景 在提交时, 误将一个目录添加到了暂存区, 而且commit 了本地库,同批次commit 的还有其他需要提交的文件。 commit 之后发现这个目录下所有的文件都不需要提交, 现在需要撤销这个提交, 使这个目录不被push到远端库。 这里以远端服务器github 为例,在Git GUI下看到的…...
百度SEO优化的特点(方式及排名诀窍详解)
百度SEO优化的特点介绍: 百度SEO优化是指对网站进行优化,使其在百度搜索引擎中获得更好的排名,进而获取更多的流量和用户。百度SEO优化的特点是综合性强、效果持久、成本低廉、投资回报高。百度的搜索算法不断更新,所以长期稳定的…...
Gin 文件上传操作(单/多文件操作)
参考地址: 单文件 | Gin Web Framework (gin-gonic.com)https://gin-gonic.com/zh-cn/docs/examples/upload-file/single-file/ 单文件 官方案例: func main() {router := gin.Default()// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)router.MaxMultipartMem…...
分类预测 | MATLAB实现KOA-CNN-LSTM开普勒算法优化卷积长短期记忆神经网络数据分类预测
分类预测 | MATLAB实现KOA-CNN-LSTM开普勒算法优化卷积长短期记忆神经网络数据分类预测 目录 分类预测 | MATLAB实现KOA-CNN-LSTM开普勒算法优化卷积长短期记忆神经网络数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现KOA-CNN-LSTM开普勒算法优化…...
Qt应用开发(基础篇)——列表视图 QListView
一、前言 QListView类继承于QAbstractItemView类,提供了一个列表或者图标视图的模型。 视图基类 QAbstractItemView QListView效果相当于Windows文件夹右键->查看->图标和列表,使用setViewMode()设置视图模式,并且提供setIconSize()函数…...
vue-6
一、声明式导航-导航链接 1.需求 实现导航高亮效果 如果使用a标签进行跳转的话,需要给当前跳转的导航加样式,同时要移除上一个a标签的样式,太麻烦!!! 2.解决方案 vue-router 提供了一个全局组件 router…...
温度在线检测技术在电力电缆线路的应用
在电力电缆的日常运行检测中,针对电缆温度的状况,所采用的电力温度在线检测技术也得到了大范围的普及。电网系统中,其单位时间内可输送的电力能源受到其温度的变化影响。因此,采用更有效的方式实时检测电缆系统运行温度࿰…...
2023年中国自动化微生物样本处理系统竞争现状及行业市场规模分析[图]
微生物检测能够对感染性疾病的病原体或者代谢物进行检测分析,是IVD的细分领域之一。2022年中国体外诊断市场规模1424亿元。 2015-2022年中国体外诊断市场规模 资料来源:共研产业咨询(共研网) 微生物检测由于样本类型多样…...
硬链接和软连接的区别
软链接(也称为软连接或符号链接)是一种特殊的文件,其内容是另一个文件的路径。当你使用软链接时,实际上是在操作另一个文件。软链接的优点是它可以跨文件系统使用,因此可以跨分区或磁盘链接文件。此外,软链…...
保护隐私与增强网络安全之网络代理技术
目录 前言 一、网络代理技术原理 二、网络代理技术类型 1. HTTP代理 2. SOCKS代理 3. DNS代理 4. 加密代理 5. 反向代理 三、网络代理技术应用 1. 加速网络访问速度 2. 绕过网络限制 3. 保护个人隐私 4. 节省带宽 5. 改善网络安全 四、网络代理技术优缺点 网络…...
【每日一题】CF1680C. Binary String | 双指针 | 简单
题目内容 原题链接 给定一个长度为 n n n 的 01 01 01 字符串,对于一个子串 s u b sub sub ,子串内部的 0 0 0 的数量为 x x x ,子串以外的 1 1 1 的数量为 y y y ,子串的代价为 m a x ( x , y ) max(x, y) max(x,y) &…...
10.selenium进阶
文章目录 1、嵌套网页1、1 什么是嵌套页面1、2 selenium获取嵌套页面的数据 2、执行JavaScript代码3、鼠标动作链4、selenium键盘事件5、其他方法5、1 选择下拉框5、2 弹窗的处理 6、selenium设置无头模式7、selenium应对检测小结 1、嵌套网页 在前端开发中如果有这么一个需…...
【安全】 Java 过滤器 解决存储型xss攻击问题
文章目录 XSS简介什么是XSS?分类反射型存储型 XSS(cross site script)跨站脚本攻击攻击场景解决方案 XSS简介 跨站脚本( cross site script )为了避免与样式css(Cascading Style Sheets层叠样式表)混淆,所以简称为XSS。 XSS是一种经常出现在web应用中的计算机安全…...
一、Excel VBA 是个啥?
Excel VBA 从入门到出门一、Excel VBA 是个啥?二、Excel VBA 简单使用 👋Excel VBA 是个啥? ⚽️1. Excel 中的 VBA 是什么?⚽️2. 为什么 VBA 很重要?⚽️3. 是否有无代码方法可以在 Excel 中实现工作流程自动化&…...
Spring Boot读取配置文件
Spring Boot 是一种用于快速构建基于Spring的应用程序的框架,它提供了很多便利的功能和约定,使开发者可以快速搭建、配置和部署应用程序。在Spring Boot中,读取配置文件是一个非常常见的任务,本文将介绍如何在Spring Boot应用程序…...
spark集群环境下,实现人口平均年龄计算
文章目录 任务目标0. 版本信息1. 计算生成renkou.txt2. 文件上传至spark3. 上传文件时,可能出现的常见错误4. 编写spark文件5. 上传集群6. 集群环境下提交任务 任务目标 在虚拟机上部署spark集群,给定renkou.txt文件,输出平均年龄 renkou.t…...
[羊城杯 2020]black cat - 文件隐写+RCE(hash_hmac绕过)
[羊城杯 2020]black cat 1 解题流程1.1 第一步1.2 第二步1.3 第三步 1 解题流程 1.1 第一步 打开网站有首歌,按F12也是提示听歌,ctf-wscan扫描就flag.php下载歌,用010打开,发现有一段内容if(empty($_POST[Black-Cat-Sheriff]) |…...
智能文件管理助手,轻松实现按数量平均分类文件,高效整理新文件夹!
在我们的电脑或移动设备中,文件管理是我们日常工作和生活中不可或缺的一部分。有时候,我们可能需要将一个文件夹中的大量文件按照数量平均分配到多个新的文件夹中,以便更好地进行整理和管理。现在,我们为您提供了一款智能文件管理…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
