【C++】单例模式「详尽版」
文章目录
- 什么是单例模式
- 如何实现单例模式
- 饿汉模式和懒汉模式
- 饿汉模式
- 懒汉模式
- 饿汉模式和懒汉模式的优缺点
- 1.饿汉模式的优缺点
- 2.懒汉模式的优缺点
什么是单例模式
C++单例模式是一种非常重要的设计模式,它只允许一个类实例化出一个对象来,并提供一个全局访问点来获取该实例。 这个模式的主要目的是控制某个类的实例化过程,以避免产生多个实例对象而导致的资源消耗或数据不一致等问题。
如何实现单例模式
实现一个单例模式的类,要做到以下几点:
私有化构造函数
,防止在外部通过构造函数直接创建出对象。禁用拷贝构造和赋值运算符
,防止在外部通过拷贝构造和赋值直接创建出对象。定义一个静态指针或者引用
,用于指向类的唯一实例。提供一个静态公有成员函数
,于返回类的唯一实例的指针或引用。这个函数通常被称为getInstance或类似的名称。「调用非静态成员函数需要一个对象,所以我们需要把该成员函数设置为私有」。
如下所示就是一个单例模式下的类
#include <iostream>
#include <memory> class Singleton {
public:// 静态公有成员函数,返回类的唯一实例 static Singleton& getInstance() {// 静态局部变量在第一次调用时初始化,且只初始化一次 return only;}// 示例成员函数 void doSomething() {std::cout << "Doing something in Singleton!" << std::endl;}private:// 私有化构造函数,防止外部直接创建实例 Singleton() {};// 私有化析构函数~Singleton() {};// 禁止拷贝构造函数和赋值运算符 Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;//定义一个静态指针或者引用static Singleton only;
};
Singleton Singleton::only;
int main() {// 获取单例实例并调用成员函数 Singleton& singleton = Singleton::getInstance();singleton.doSomething();// 尝试再次获取单例实例(应为同一个实例) Singleton& anotherSingleton = Singleton::getInstance();anotherSingleton.doSomething();return 0;
}
单例模式的设计思路有很多,但是我们都需要满足上面的几点。
饿汉模式和懒汉模式
在单例模式下,又细分为经典的饿汉模式和懒汉模式,我们一起来了解一下:
饿汉模式
什么是饿汉模式?
饿汉模式,这个名词很形象,大家可以想象为很“饥饿
”,实例在类加载的时候就被创建
,所以一开始还没有进入到main函数中就要创建实例。
如何实现饿汉模式?
我们刚刚的代码实际上就是饿汉模式的一种。我们需要定义一个类的静态成员变量【如刚刚代码中的static Singleton only】。
代码如下:
#include <iostream>
#include <memory> class Singleton {
public:// 静态公有成员函数,返回类的唯一实例 static Singleton& getInstance() {// 静态局部变量在第一次调用时初始化,且只初始化一次 return only;}// 示例成员函数 void doSomething() {std::cout << "Doing something in Singleton!" << std::endl;}private:// 私有化构造函数,防止外部直接创建实例 Singleton() {};// 私有化析构函数~Singleton() {};// 禁止拷贝构造函数和赋值运算符 Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;//定义一个静态指针或者引用static Singleton only;
};
Singleton Singleton::only;
int main() {// 获取单例实例并调用成员函数 Singleton& singleton = Singleton::getInstance();singleton.doSomething();// 尝试再次获取单例实例(应为同一个实例) Singleton& anotherSingleton = Singleton::getInstance();anotherSingleton.doSomething();return 0;
}
懒汉模式
什么是懒汉模式?
懒汉模式,顾名思义在懒
.指的是类对象在使用时才会被创建。
如何实现懒汉模式
我们将饿汉模式稍加改造即可:
方法1:
代码:这是一种线程安全的懒汉模式
单例模式 懒汉版
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>using namespace std;
mutex mtx;
class Singleton1
{
public:static Singleton1* GetOnly(){if (only == nullptr){ unique_lock<mutex>lock(mutex);if (only == nullptr){only = new Singleton1();}}return only;}void print(){cout << "hello world" << endl;}
private:Singleton1() {};~Singleton1() {};Singleton1(const Singleton1&) = delete;Singleton1& operator=(const Singleton1&) = delete;static Singleton1* only;};Singleton1* Singleton1::only=nullptr;
int main()
{Singleton1* t1 = Singleton1::GetOnly();t1->print();
}
有没有第二种设计懒汉模式的方案呢?有的;
方案二:
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>using namespace std;
mutex mtx;
class Singleton1
{
public:static Singleton1* GetOnly(){static Singleton1 install;return &install;}void print(){cout << "hello world" << endl;}
private:Singleton1() {};~Singleton1() {};Singleton1(const Singleton1&) = delete;Singleton1& operator=(const Singleton1&) = delete;static Singleton1* only;};Singleton1* Singleton1::only=nullptr;
int main()
{Singleton1* t1 = Singleton1::GetOnly();t1->print();
}
改动的地方如下:
但是这种方案是不是线程安全的呢?
是的,原因如下:
1.静态局部变量在程序启动阶段就已经被分配内存空间了,但是它的的初始化却是在第一次运行到它的时候,如果我们不调用GetOnly()方法,这个静态局部变量是不会被初始化的。
2.在多线程的情况下,可能会出现对个线程同时访问GetOnly()的情况,但是静态局部变量的初始化,在汇编指令上,已经自动添加了线程互斥指令了,所以总的来说是安全的。
饿汉模式和懒汉模式的优缺点
1.饿汉模式的优缺点
饿汉模式的优点:
线程安全:在类加载的时候就创建实例,不存在多线程环境下的线程安全问题(还没进入主函数就创建完实例了,所以不用担心线程安全问题)。
饿汉模式的缺点:
可能会造成资源浪费:在程序运行过程中始终存在实例,可能会占用一定的资源。
不支持延迟加载:无法实现延迟加载的特性。
2.懒汉模式的优缺点
懒汉模式的优点:
延迟加载:在第一次调用时才创建实例,节省资源。
节约内存:只有在需要时才创建实例,避免资源浪费。
懒汉模式的缺点:
线程安全性问题:在多线程环境下,需要额外的同步措施来保证线程安全。
可能存在性能问题:在第一次调用时需要进行实例化,可能会影响程序性能。
相关文章:

【C++】单例模式「详尽版」
欢迎来到 破晓的历程的 博客 ⛺️不负时光,不负己✈️ 文章目录 什么是单例模式如何实现单例模式饿汉模式和懒汉模式饿汉模式懒汉模式饿汉模式和懒汉模式的优缺点1.饿汉模式的优缺点2.懒汉模式的优缺点 什么是单例模式 C单例模式是一种非常重要的设计模式…...

MongoDB集群模式详解及应用实战
目录 本节课内容: 集群搭建 1.创建3个目录: 2.编辑配置文件 编辑 3.启动: 4.看看: 5.另外,两个如上1,2,3步骤操作 ,但是日志目录,端口什么的需要改一下即可。 …...

接着上一篇stp 实验继续
理论看上一篇,我们直接实验 首先找出root 桥 很明显 sw1 为root 桥,所谓sw1 &a…...

怎么将手机备忘录传送至电脑
在数字化时代,手机备忘录已成为我们生活中不可或缺的一部分。无论是记录购物清单、工作事项,还是灵感闪现的瞬间,手机备忘录都能随时记录下这些宝贵的信息,帮助我们防止遗忘。然而,有时候我们需要将这些备忘录内容转移…...
解决触摸屏屏幕乱动的问题:E: 无法定位软件包 libinput
在 Ubuntu 中,你可能已经有 libinput 库,它通常默认包含在系统中。如果你想使用 libinput 来管理输入设备(例如触摸屏或触摸板),通常不需要安装额外的软件包,而是直接使用系统自带的工具。 不过࿰…...

RISC-V笔记——基础
1. 前言 RISC-V旨在支持广泛的定制和专业化。RISC-V的ISA是由一个基本整型ISA和其它对基本ISA的可选扩展组成。每个整型ISA可以使用一个或多个可选的ISA扩展进行扩展。 基本整型ISA精选了最小的一组指令,这些指令足以为编译器、汇编器、链接器和操作系统提供足够的…...
「Kafka」Kafka消息可靠性和重复消费问题(五)
在 Kafka 中,实现消息的可靠性和避免重复消费是保证数据一致性和系统稳定性的关键。Kafka 提供了多种机制来实现这两个目标。 1. Kafka 消息可靠性 Kafka 的可靠性主要体现在消息的投递和存储上,以确保消息不会丢失。具体来说,有以下几个措…...

现代身份和访问管理 IAM 如何降低风险
您的公司是否仍在使用 1998 年时的身份管理系统?仅凭用户名和密码就能登录本地网络并访问几乎所有资源吗? 虽然大多数企业已经转向现代身份和访问管理(IAM) 平台,但成千上万的企业和其他组织仍然依赖过时的用户名/密码系统。 如果你看一下传…...

2024年江西省职业院校技能大赛(高职组)信息安全管理与评估”赛项竞赛规程
附件 1 2024年江西省职业院校技能大赛(高职组)信息安全管理与评估”赛项竞赛规程附件 1 一、赛项名称 信息安全管理与评估赛 二、竞赛目的 通过赛项检验参赛选手网络组建、按照等保要求加固网络、安全架构、 渗透测试等技术能力,检验参赛队计划组织和团队协作等综合…...
在 Koa 中,中间件函数的参数ctx是什么?
在 Koa 中,ctx 是指 context 对象,它是请求与响应的上下文,封装了 request 和 response。每当 Koa 收到一个 HTTP 请求时,都会为该请求创建一个 ctx 对象,ctx 使开发者可以通过它方便地获取请求信息并设置响应。 ctx …...

在 Gitlab 中使用 ChatGPT 进行 CodeReview
ChatGPT集成Gitlab,实现自动代码审计并进行评论,为软件开发团队提供高效、智能的代码审查解决方案。支持其他模型如通义千问等 自动触发与及时响应:利用Gitlab的Webhook功能,实现代码提交、合并请求和标签创建等事件的自动触发。一…...

解决新版Android studio不能连接手机的问题
我要说的是一个特例,装了22年的版本AS可以正常连接手机,装了23年以后新版本,AS不能正常连接手机了,但是在CMD控制台可以正常的执行adb命令,并且CMD和AS都是指向D:\android_sdk\platform-tools\adb.exe 一、 为什么会出…...
arcgis for js点位渲染与实际坐标不一致且popupTemplate偏移
问题描述 arcgis for js 鼠标点击地图时的经纬度, 使用该经纬度加载一个Point点, 该Point点渲染位置与实际经纬度不一致(存在偏差)该Point点设置popupTemplate弹窗, 点击Point点无法弹出 (位置偏移导致) 原因 地图容器或更外层元素CSS的scale属性导致...

定点数和浮点数的详细介绍(一)定义、范围、位宽
1.定点数 1.1定点数描述 定点数包括定点小数(纯小数)、定点整数(纯整数)、整数和小数位数固定的实数。 1.2定点小数: 小数点默认在符号位后面,首位为符号位,其他为数值位(在用二进制代表小数时,例如0xFF,就表示0.5+0.25+0.125+0.0625+0.03125........) 例如,用…...
Redis: 集群环境搭建,集群状态检查,分析主从日志,查看集群信息
集群环境搭建 在 Redis 5版本以前是用 Ruby 来搭建集群,在后面的版本中仍保留了相关功能可以再源码src目录中,看到 redis-trib.rb 这个东西,只是现在用这种方式搭建的少了我们看新的版本是怎样搭建集群的,新版构建集群的方式简单…...

『网络游戏』动态界面制作创建角色UI【02】
将上一章的登录界面隐藏 创建空物体重命名为CreateWnd 自适应铺满父物体 创建image重命名为bg并铺满 将以下资源图片放进Art文件夹 设置为精灵模式 填充背景 创建介绍Image面板与角色按钮 制作将3D模型动态防止UI界面上 首先创建RawImage 创建RenderTextures文件夹 创建Render…...
CMake 教程跟做与翻译 2
目录 STEP 1(Extra A):指定C的版本 STEP1(Extra B): 为我们的项目添加版本信息与配置的头文件 Reference STEP 1(Extra A):指定C的版本 有的时候,我们会是对一个比较年老的项目进行构建。这个时候,我们可能就需要限制一下使用的…...

Linux 之 安装软件、GCC编译器、Linux 操作系统基础
安装软件、GCC编译器、Linux 操作系统基础 学习任务: 安装 Vmware虚拟机、掌握Ubuntu 系统的使用认识 Ubuntu 操作系统的终端和 Shell掌握软件安装、文件系统、掌握磁盘管理与解压缩掌握 VIM 编辑器、Makefile 基本语法熟悉 Linux 常见指令操作 安装好开发软件&…...

[CTF夺旗赛] CTFshow Web13-14 详细过程保姆级教程~
前言 CTFShow通常是指网络安全领域中的“Capture The Flag”(夺旗赛)展示工具或平台。这是一种用于分享、学习和展示信息安全竞赛中获取的信息、漏洞利用技巧以及解题思路的在线社区或软件。参与者会在比赛中收集“flag”,通常是隐藏在网络环境中的数据或密码形…...

【Matlab】Matlab 导入数据.csv或者.xlsx文件,然后使用这些数据来绘制图表
Matlab 导入数据.csv或者.xlsx文件,然后使用这些数据来绘制图表 初始数据 filename C:\Users\jia\Desktop\yadian\data\1Hz 2024_09_12 17_10_06.csv; 代码: clc;clear close all; % 读取Excel文件 filename C:\Users\jia\Desktop\yadian\data\1Hz …...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...