C++单例模式各种实现方式,终极版即简单又线程安全,无脑用就完了

news2024/11/25 4:31:58

📋 前言

  • 🖱 博客主页:在下马农的碎碎念
  • 🤗 欢迎关注🔎点赞👍收藏⭐️留言📝
  • ✍ 本文由在下马农原创,首发于CSDN
  • 📆 首发时间:2023/8/25
  • 📅 最近更新时间:2023/08/28
  • 🤵 此马非凡马,房星本是星。向前敲瘦骨,犹自带铜声。
  • 📇 系列文章目录: 暂无
  • 🙏作者水平有限,如发现错误,请留言轰炸哦!万分感谢!

须知少年凌云志,曾许人间第一流
——清·吴庆坻《题三十小像》

在这里插入图片描述
以下是正文

一、什么是单例模式?

  单例模式是一种常用的设计模式,它保证一个类只有一个实例,并且提供了全局访问该实例的方法。在C++中,单例模式的实现方式有多种。在单例模式中,通常使用一个静态方法或者一个静态变量来保存实例。这个静态方法或者静态变量可以被所有需要访问该实例的对象共享,并且在第一次调用时创建实例。之后每次调用该方法或者访问该变量时,都返回同一个实例。


单例模式的特点:

  • 一个类只有一个实例
  • 该实例在程序运行的整个周期内始终存在
  • 该实例可以被全局访问

  单例模式可以用于控制资源的访问,例如数据库连接池、线程池等。它还可以用来确保系统中某些组件只有一个实例,例如配置文件管理器、日志记录器等。

二、单例模式的实现方式

2.1 饿汉式:

特点:实现简单,线程安全,但可能造成内存浪费
适用情况: 单例对象在程序运行过程中频繁被调用

  饿汉式是最简单的一种单例模式实现方式,它在程序启动时就创建了单例对象,因此也被称为“急切创建”方式。这种方式的优点是实现简单且线程安全,因为这种方式在单例对象被使用之前就已经创建好了,因此不存在多线程环境下的竞争问题,但是缺点是如果该对象很少被使用,会造成内存浪费。
  饿汉式单例模式的实现方式一般是将单例模式定义为静态成员变量,并在类定义中就初始化它,这样单例对象就会在类装载的时候进行创建,在整个程序结束时按序销毁。
具体实现如下:

class Singleton {
public:
    static Singleton* getInstance();
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton &signal);
    const Singleton &operator=(const Singleton &signal);
private:
	// 唯一的单例对象
    static Singleton *instance_;
};
// 代码一运行就初始化创建实例 ,本身就线程安全
Singleton* Singleton::instance_= new (std::nothrow) Singleton();
Singleton* Singleton::getInstance() {
    return instance_;
}
Singleton::Singleton() {}
Singleton::~Singleton() {}

在上面的示例代码中,Singleton类的instance_成员变量是一个静态成员变量,它被定义为私有的,只能通过getInstance()方法来访问。getInstance()方法返回的是instance_的引用,通过这种方式来保证只有一个实例被创建。由于instance_被定义为静态成员变量,它会在程序启动时就被初始化。由于该方式在程序启动时就创建了单例对象,因此被称为“饿汉式单例模式”。

2.2 懒汉式

特点:延迟创建对象实例,避免了不必要的资源消耗,但是在多线程环境中线程不安全,需要加锁保证线程安全
适用情况: 单例对象的创建和初始化过程比较耗时,而且在程序运行过程中可能并不总是需要使用该对象,对资源敏感时也不叫使用,如果线程安全没什么要求,也可以用

懒汉式是另一种常见的单例模式实现方式,它在第一次访问单例对象时才进行创建。具体实现如下:

头文件Singleton.h:

class Singleton {
private:
    // 私有的构造函数,防止外部创建对象
    Singleton();
    // 单例对象的指针
    static Singleton* instance;
public:
    // 获取单例对象的静态方法
    static Singleton* getInstance();
};

源文件Singleton.cpp

#include "Singleton.h"
Singleton* Singleton::instance = nullptr;
Singleton::Singleton() {
    // 进行初始化操作
}
Singleton* Singleton::getInstance() {
    if (instance == nullptr) {
        instance = new Singleton();
    }
    return instance;
}

  上述代码中,Singleton类的构造函数是私有的,防止外部直接创建对象。instance指针被初始化为nullptr。在getInstance()方法中,首先检查instance是否为nullptr,如果是,则说明还没有创建单例对象,需要进行创建。创建成功后,将其赋值给instance指针,并返回该指针。`

  注意懒汉式单例模式的特点是在第一次请求时才创建对象,避免了程序启动时的资源浪费,但需要注意在多线程环境下的线程安全性以上示例是简单的单线程示例,在多线程环境下需要添加线程安全的措施,比如使用互斥锁或双重检查锁定等机制来保证线程安全性。

2.3 双重检查锁

C++中的双检锁(Double-Checked Locking)实现单例模式是一种在多线程环境下延迟创建单例对象的方式,通过使用双重检查来提高性能。

头文件:

class Singleton {
public:
    // 获取单例实例的静态方法
    static Singleton* getInstance();
    // 删除拷贝构造函数和赋值运算符重载,确保单例的唯一性
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
private:
    // 私有构造函数,防止外部实例化
    Singleton();

    static Singleton* instance; // 单例实例指针
    static std::mutex mutex;    // 互斥锁
};

源文件:

#include "Singleton.h"

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;

Singleton::Singleton() {
    // 构造函数
}
Singleton* Singleton::getInstance() {
    if (instance == nullptr) {
        std::lock_guard<std::mutex> lock(mutex); // 加锁

        if (instance == nullptr) {
            instance = new Singleton();
        }
    }
    return instance;
}

注意: 双检锁(Double-Checked Locking)在某些情况下可能不是线程安全的,尤其是在特定的编译器和硬件平台上。这是由于编译器和处理器的优化行为可能导致双检锁失效,从而导致多个线程同时创建实例。

具体来说,双检锁的问题源于指令重排序(instruction reordering)和多核处理器的内存可见性(memory visibility)。编译器和处理器为了提高执行效率,可能会对代码中的指令进行重排序,而不考虑程序员的意图。这种重排序可能会导致在检查 instance 是否为 nullptr 之后,但在实际创建实例之前,另一个线程就已经读取到了一个尚未完全初始化的实例。

2.4 静态局部变量(推荐!!!实现简单,轻松易学)

使用静态局部变量的方式实现单例模式是一种简洁且线程安全的方法。无需显式使用互斥锁或原子操作,能够在需要时按需创建单例实例,并且在整个程序生命周期内保持单例的唯一性。

头文件:

class Singleton {
public:
    static Singleton& getInstance();

    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

private:
    Singleton();
};

源文件:

#include "Singleton.h"
Singleton& Singleton::getInstance() {
    static Singleton instance;
    return instance;
}
Singleton::Singleton() {
    // 构造函数
}

在上述代码中,getInstance() 方法返回一个对静态局部变量 instance 的引用。静态局部变量在函数首次调用时被初始化,并且在整个程序生命周期内保持存在。由于静态局部变量在 C++ 中具有线程安全的保证,因此无需显式使用互斥锁或原子操作来保护实例的创建过程。

总结

以上就是C++单例模式的所有实现方式。不同的实现方式在性能、线程安全等方面有所区别,具体实现方式应该根据实际情况进行选择,同时,需要注意在多线程环境下进行线程安全的处理,推荐优先使用静态局部变量方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1043130.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学生宿舍管理系统(前端java+后端Vue)实现-含前端与后端程序

界面介绍 登录 ###宿舍管理 ###菜单管理 ###角色管理 ###班级管理

编程每日一练(多语言实现):判断偶数

文章目录 一、实例描述二、技术要点三、代码实现3.1 C 语言实现3.2 Python 语言实现3.3 Java 语言实现 一、实例描述 利用单条件单分支选择语句判断输入的一个整数 是否是偶数。 运行程序&#xff0c;输入一个 整数18&#xff0c; 然后按回车键&#xff0c;将提示该数字是偶数…

性能压力测试的定义及步骤是什么

在今天的数字化时代&#xff0c;软件系统的性能和稳定性对于企业的成功至关重要。为了确保软件在高负载和压力情况下的正常运行&#xff0c;性能压力测试成为了不可或缺的环节。本文将介绍性能压力测试的定义、步骤。 一、性能压力测试的定义和目标 性能压力测试是通过模拟实际…

Spring整合RabbitMQ——生产者

添加依赖坐标&#xff0c;在producer和consumer模块的pom文件中各复制一份。 配置producer的配置文件 配置producer的xml配置文件 编写测试类发送消息

[GXYCTF2019]BabySQli 1

进去就是两个登录框 先试了试adminadmin&#xff0c;然后显示wrong pass 试了下万能密码 1 or 11 查看下页面源代码 放到瑞士军刀解密一下 用fuzz字典跑一下 会发现order被过滤了 所以order用Order来过滤 admin Order by 3-- 得到字段数为3 然后判断一下注入点 判断得到这题…

ESD门禁闸机的用途及优点

ESD门禁闸机是一种专门用于防止静电干扰的门禁设备&#xff0c;其主要用途包括&#xff1a; 防止静电干扰&#xff1a;ESD门禁闸机可以有效地防止静电干扰&#xff0c;保护电子元器件、电路板等敏感设备不受静电破坏。 控制人员进出&#xff1a;ESD门禁闸机可以通过身份验证等…

后端配置(宝塔):处理php禁用函数

一、找到php的文件路径 在软件商店中&#xff0c;找到已安装文件&#xff0c;选择需要更改的php文件&#xff0c;选择“设置” 二、选择需要取消禁用的文件进行删除 扩展&#xff1a;可解决 The Process class relies on proc_open, which is not available on your PHP i nst…

deepin DTK(Development ToolKit)已正式适配 Qt6!

导读近日&#xff0c;深度 deepin 宣布 deepin DTK&#xff08;Development ToolKit&#xff09;已正式适配 Qt6 (6.4.2)&#xff0c;实现全面升级。 DTK 作为 deepin 基于 Qt 开发的一整套简单且实用的通用开发框架&#xff0c;处于 deepin 操作系统中的核心位置&#xff0c;此…

基于YOLOv8模型的空中视角下车辆检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的空中视角下车辆检测系统可用于日常生活中检测与定位bus、cycle、truck、van、vehicle目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统…

[AFCTF 2018]你能看出这是什么加密么

最开始是我对rsa的小小的理解 rsa也就是非对称加密算法&#xff0c;拥有公开的加密密钥和解密密钥&#xff0c;这也是我们写脚本的基础 选取素数p和q&#xff0c;计算乘积npq&#xff0c;以及(n)(p-1)(q-1)。&#xff08;欧拉函数&#xff09; 选择一个e值作为密钥…

组合数4 高精度计算组合数

一般来说需要高精乘和高精除&#xff0c;但化简为质因子形式后只用高精乘。 一个阶乘n中因子p的个数&#xff1a; #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \nusing namespace std;typedef pair<int, int&…

开源一个基于的rt-thread系统的烟感采集系统

一、硬件 CPU&#xff1a;stm32f401 NBIOT模块&#xff1a;移远BC26 存储&#xff1a;W25Q128JVSIQTR 扩展&#xff1a;HC595输出&#xff0c;165输入 二、软件应用 FAL&#xff1a;分区 littlefs: 应用存储用的文件系统 EashFlash&#xff1a;日记存储、系统变量存储 kawaii_…

AP2400 DC-DC降压恒流驱动器 汽车摩托LED大灯电源驱动 全亮半亮瀑闪三功能循环

产品特点 宽输入电压范围&#xff1a;5V&#xff5e;100V 可设定电流范围&#xff1a;10mA&#xff5e;6000mA 固定工作频率&#xff1a;150KHZ 内置抖频电路&#xff0c;降低对其他设备的 EMI干扰 平均电流模式采样&#xff0c;恒流精度更高 0-100%占空比控制&#xff0…

邮件功能-python中的SMTP协议邮件发送

文章目录 一、SMTP协议邮件准备二、smtplib模块1.使用smtplib封装一个邮件类2.发送邮件 补充 一、SMTP协议邮件准备 需要一个smtp服务器 二、smtplib模块 smtplib模块是python自带的模块 1.使用smtplib封装一个邮件类 import smtplib import logging # 加入日志&#xff…

向着趋势奔跑:银行客户中心转型,重构商业模式是关键

随着金融市场化改革的推进 国内银行同业间的竞争日趋激烈 各商业银行在全新的监管要求和市场环境下 纷纷开始推行“以客户为中心”的经营新模式 迅速提升核心竞争力 然而&#xff01;&#xff01;&#xff01; 奇怪的事情发生了 &#x1f447; &#x1f447; &#x1f44…

DP读书:《openEuler操作系统》(三)操作系统的分类

操作系统的发展趋势 微内核库操作系统外内核多内核离散化内核openEuler操作系统简介 操作系统处于应用层与硬件层之间&#xff0c;上看应用、下看硬件。 应用层上&#xff0c;无人驾驶、工业驾驶等场景中&#xff0c;操作系统的可靠性被放在更重要的位置&#xff0c;微内核更受…

即刻报名!飞桨黑客马拉松第五期开启,创新挑战等你来!

新赛制&#xff0c;新玩法 飞桨黑客马拉松第五期 全新挑战&#xff0c;重磅回归&#xff01; 开源贡献个人挑战赛、大模型应用与创意赛、飞桨护航计划集训营 三大赛道&#xff0c;邀你挑战&#xff01; 多难度梯度开源任务、大模型应用创意挑战、导师1V1指导开发实践 硬核较量一…

SW - 清除零件实体表面上无用的凸起

文章目录 SW - 清除零件实体表面上无用的凸起概述笔记END SW - 清除零件实体表面上无用的凸起 概述 给顶部相机做了一个散射罩, 防止灯光太亮和不均匀. 3D打印的版本. 回来试验后, 要改进一下. 改进完了之后, 发现零件表面有多余的凸起, 看了好多资料, 没看到适用的方法. 如…

亮相“外滩金融峰会” 百望云实力入选“融城杯金融科技创新十佳案例”

近日&#xff0c;第五届“外滩金融峰会”在上海召开&#xff0c;百望云受邀出席峰会&#xff0c;与全球财经政要、机构高管与学界领袖齐聚外滩&#xff0c;分享真知灼见&#xff0c;以对话推动共识。 本届峰会由中国金融四十人论坛&#xff08;CF40&#xff09;与中国国际经济交…

微信加人不频繁的技巧,快码住

微信加人不频繁有哪些技巧&#xff1f; 1、尽量通过手机联系人进行添加 如果对方是你的手机联系人&#xff0c;添加好友可以更方便。不需要像常规方法搜索手机号或者微信号&#xff0c;直接通过手机联系人添加即可。这种方式系统不会认为你频繁加好友。 2、定时定量地去添加好…