当前位置: 首页 > news >正文

【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++】单例模式「详尽版」

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 什么是单例模式如何实现单例模式饿汉模式和懒汉模式饿汉模式懒汉模式饿汉模式和懒汉模式的优缺点1.饿汉模式的优缺点2.懒汉模式的优缺点 什么是单例模式 C单例模式是一种非常重要的设计模式&#xf…...

MongoDB集群模式详解及应用实战

目录 本节课内容&#xff1a; 集群搭建 1.创建3个目录&#xff1a; 2.编辑配置文件 ​编辑 3.启动&#xff1a; 4.看看&#xff1a; 5.另外&#xff0c;两个如上1&#xff0c;2&#xff0c;3步骤操作 &#xff0c;但是日志目录&#xff0c;端口什么的需要改一下即可。 …...

接着上一篇stp 实验继续

理论看上一篇&#xff0c;我们直接实验 首先找出&#xff52;&#xff4f;&#xff4f;&#xff54; 桥 很明显 &#xff53;&#xff57;&#xff11; 为&#xff52;&#xff4f;&#xff4f;&#xff54; 桥&#xff0c;所谓&#xff53;&#xff57;&#xff11;  &a…...

怎么将手机备忘录传送至电脑

在数字化时代&#xff0c;手机备忘录已成为我们生活中不可或缺的一部分。无论是记录购物清单、工作事项&#xff0c;还是灵感闪现的瞬间&#xff0c;手机备忘录都能随时记录下这些宝贵的信息&#xff0c;帮助我们防止遗忘。然而&#xff0c;有时候我们需要将这些备忘录内容转移…...

解决触摸屏屏幕乱动的问题:E: 无法定位软件包 libinput

在 Ubuntu 中&#xff0c;你可能已经有 libinput 库&#xff0c;它通常默认包含在系统中。如果你想使用 libinput 来管理输入设备&#xff08;例如触摸屏或触摸板&#xff09;&#xff0c;通常不需要安装额外的软件包&#xff0c;而是直接使用系统自带的工具。 不过&#xff0…...

RISC-V笔记——基础

1. 前言 RISC-V旨在支持广泛的定制和专业化。RISC-V的ISA是由一个基本整型ISA和其它对基本ISA的可选扩展组成。每个整型ISA可以使用一个或多个可选的ISA扩展进行扩展。 基本整型ISA精选了最小的一组指令&#xff0c;这些指令足以为编译器、汇编器、链接器和操作系统提供足够的…...

「Kafka」Kafka消息可靠性和重复消费问题(五)

在 Kafka 中&#xff0c;实现消息的可靠性和避免重复消费是保证数据一致性和系统稳定性的关键。Kafka 提供了多种机制来实现这两个目标。 1. Kafka 消息可靠性 Kafka 的可靠性主要体现在消息的投递和存储上&#xff0c;以确保消息不会丢失。具体来说&#xff0c;有以下几个措…...

现代身份和访问管理 IAM 如何降低风险

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

2024年江西省职业院校技能大赛(高职组)信息安全管理与评估”赛项竞赛规程

附件 1 2024年江西省职业院校技能大赛(高职组)信息安全管理与评估”赛项竞赛规程附件 1 一、赛项名称 信息安全管理与评估赛 二、竞赛目的 通过赛项检验参赛选手网络组建、按照等保要求加固网络、安全架构、 渗透测试等技术能力&#xff0c;检验参赛队计划组织和团队协作等综合…...

在 Koa 中,中间件函数的参数ctx是什么?

在 Koa 中&#xff0c;ctx 是指 context 对象&#xff0c;它是请求与响应的上下文&#xff0c;封装了 request 和 response。每当 Koa 收到一个 HTTP 请求时&#xff0c;都会为该请求创建一个 ctx 对象&#xff0c;ctx 使开发者可以通过它方便地获取请求信息并设置响应。 ctx …...

在 Gitlab 中使用 ChatGPT 进行 CodeReview

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

解决新版Android studio不能连接手机的问题

我要说的是一个特例&#xff0c;装了22年的版本AS可以正常连接手机&#xff0c;装了23年以后新版本&#xff0c;AS不能正常连接手机了&#xff0c;但是在CMD控制台可以正常的执行adb命令&#xff0c;并且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 来搭建集群&#xff0c;在后面的版本中仍保留了相关功能可以再源码src目录中&#xff0c;看到 redis-trib.rb 这个东西&#xff0c;只是现在用这种方式搭建的少了我们看新的版本是怎样搭建集群的&#xff0c;新版构建集群的方式简单…...

『网络游戏』动态界面制作创建角色UI【02】

将上一章的登录界面隐藏 创建空物体重命名为CreateWnd 自适应铺满父物体 创建image重命名为bg并铺满 将以下资源图片放进Art文件夹 设置为精灵模式 填充背景 创建介绍Image面板与角色按钮 制作将3D模型动态防止UI界面上 首先创建RawImage 创建RenderTextures文件夹 创建Render…...

CMake 教程跟做与翻译 2

目录 STEP 1(Extra A)&#xff1a;指定C的版本 STEP1(Extra B): 为我们的项目添加版本信息与配置的头文件 Reference STEP 1(Extra A)&#xff1a;指定C的版本 有的时候&#xff0c;我们会是对一个比较年老的项目进行构建。这个时候&#xff0c;我们可能就需要限制一下使用的…...

Linux 之 安装软件、GCC编译器、Linux 操作系统基础

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

[CTF夺旗赛] CTFshow Web13-14 详细过程保姆级教程~

前言 ​ CTFShow通常是指网络安全领域中的“Capture The Flag”(夺旗赛)展示工具或平台。这是一种用于分享、学习和展示信息安全竞赛中获取的信息、漏洞利用技巧以及解题思路的在线社区或软件。参与者会在比赛中收集“flag”&#xff0c;通常是隐藏在网络环境中的数据或密码形…...

【Matlab】Matlab 导入数据.csv或者.xlsx文件,然后使用这些数据来绘制图表

Matlab 导入数据.csv或者.xlsx文件&#xff0c;然后使用这些数据来绘制图表 初始数据 filename C:\Users\jia\Desktop\yadian\data\1Hz 2024_09_12 17_10_06.csv; 代码&#xff1a; clc;clear close all; % 读取Excel文件 filename C:\Users\jia\Desktop\yadian\data\1Hz …...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...