创建型模式-----(单例模式)

news2024/10/23 9:10:57

目录

基本概念

饿汉式:

懒汉式:

         上锁双判空版本

std::call_once版本:

C++11标准后局部静态变量版本:

项目中单例模板的应用


基本概念

单例模式:在程序运行期间只有一份,与程序生存周期一样,因此无需手动释放内存,由程序结束后系统自动回收进程内存。
类单例的方式:

              1.构造函数私有化 禁止用户随便构造。
              2.创造属于类的私有静态实例并仅限通过静态函数访问实例;
              3.拷贝和赋值构造需要私有化或者禁掉。
              4.考虑多线程竞态可能创建多个实例等。

UML图:

饿汉式:

类加载即实例化,无线程竞争问题;但可能在实际使用前很久该单例一直未使用,空耗内存。

class EhanSingle
{
public:
	EhanSingle(const EhanSingle&) = delete;
	EhanSingle&operator = (const EhanSingle&) = delete;
	~EhanSingle() = delete;
	static EhanSingle* getInstance()
	{
		return instance;
	}
private:
	EhanSingle() = default;
	static EhanSingle *instance;

};
//类加载即实例化 无线程竞争问题
EhanSingle* EhanSingle::instance = new EhanSingle;

懒汉式:

上锁双判空版本

        只有在程序实际需要使用单例实例时,才进行初次创建,内存效率较高,但需要考虑线程竞态问题。

        该代码中使用了互斥锁+双层判空机制防止产生多个实例;同时使用原子变量防止实例在创建时候由于指令重排可能导致的实例构建失败。

//懒汉  
#include<atomic>
#include<mutex>
class LanHanSignle
{
public:
	LanHanSignle(const LanHanSignle&) = delete;
	LanHanSignle& operator = (const LanHanSignle&) = delete;
	~LanHanSignle() = delete;
	static LanHanSignle*getInstance()
	{
		LanHanSignle *instance = atom_instance.load();
		if (instance == nullptr)
		{
			mtx.lock(); //上锁 双层判空防止多线程产生多个
			if (instance == nullptr)
			{
				//atomic存储操作是为了防止指令重排序 
				//1分配内存 2 在内存构建实例 3 指针指向内存
				//重排后可能1,3,2 当2出错后指针指向内存为空但是实例构造失败
				instance = new (std::nothrow) LanHanSignle();
				atom_instance.store(instance);
			}
			mtx.unlock();
		}
		return instance;
	}
private:
	LanHanSignle();
	static std::mutex mtx;
	static std::atomic<LanHanSignle*> atom_instance;
};

std::call_once版本:

        对于只执行一次构造可以采用std::call_once进行延迟实例构造,而且可以避免懒汉需要上锁的问题;但同时也存在一次构造失败会导致后续不会重新构造实例问题

class LanHanSingleton
{
public:
	LanHanSingleton(const LanHanSingleton&) = delete;
	LanHanSingleton& operator = (const LanHanSingleton&) = delete;
	static LanHanSingleton* getInstance()
	{
		//如果第一次构造失败后续会一直返回错误的instance 
		std::call_once(once_flag, LanHanSingleton::createInstance);
		return instance;
	}
private:
	static LanHanSingleton* instance;
	static std::once_flag once_flag;
	static void createInstance() { instance = new(std::nothrow) LanHanSingleton; }
	LanHanSingleton() = default;
	~LanHanSingleton() = default;
};

LanHanSingleton* LanHanSingleton::instance = nullptr;
std::once_flag LanHanSingleton::once_flag;

C++11标准后局部静态变量版本:

        c++11 标准保证指令逻辑进入未被初始化的静态变量,所有并发操作应该等待变量初始化完成;由此可以简化懒汉的线程竞态产生的问题。

//静态局部变量 简化懒汉式
class LanHanSingleStaticLocal
{
public:
	LanHanSingleStaticLocal(const LanHanSingleStaticLocal&) = delete;
	LanHanSingleStaticLocal& operator = (const LanHanSingleStaticLocal&) = delete;
	static LanHanSingleStaticLocal* getInstance()
	{
		//c++11 标准保证指令逻辑进入未被初始化的声明变量 
		//所有并发操作应该等待变量初始化完成
		static LanHanSingleStaticLocal instance;
		return&instance;
	}
private:
	LanHanSingleStaticLocal() = default;
	//不能=delete 局部静态变量退出需要调用
	~LanHanSingleStaticLocal() = default;
};

项目中单例模板的应用

        在项目中一般会有许多全局唯一的变量,如软件的配置文件、数据缓存、数据库的连接池、枚举映射、计费单元、用户单元等等;可以使用单例模板对这些类进行简化编写。

如采用局部静态变量的单例模板如下:

template<typename T>
class Singleton
{
public:
	Singleton(const Singleton&) = delete;
	Singleton& operator = (const Singleton&) = delete;
	static T* getInstance()
	{
		static T instance;
		return&instance;
	}
private:
	Singleton() = default;
	~Singleton() = default;
};

新建一个单例缓存类如下:

#pragma once
#include<string>
#include<map>
#include "Signleton.h"
using namespace std;

//宏便于后续使用
#define g_DataCache  Singleton<CacheHelper>::getInstance()
class CacheHelper
{
    //声明友元 便于单例调用该类私有构造函数
	friend Singleton<CacheHelper>;
public:
	string getValue(const string&key) const;
	void setValue(const string&key, const string&value);
	/*
	...
	*/
private:
	CacheHelper() {}
	~CacheHelper() {};
	std::map<string, string>m_CacheMap;
	/*
	...
	*/
};

使用单例

g_DataCache->setValue("CameraSerialNo","DTS-TP303");
string cameraSerialStr = g_DataCache->getValue("CameraSerialNo");

线程池中的应用:

#define g_Get_EtcThreadPool Singleton<EtcThreadPool>::getInstance()

class EtcThreadPool 
{
public:
	friend Singleton<EtcThreadPool>;
	QThreadPool *GetEtcThreadPool();
	void DestoryThreadPool();
private:
	EtcThreadPool() = default;
	~EtcThreadPool() = default;
	QMutex m_EtcPoolMutex;
	QThreadPool *m_EtcThreadPool = nullptr;
	void InitEtcThreadPool();
};

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

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

相关文章

对比学习论文随笔 1:正负样本对(Contrastive Learning 基础论文篇)

为了阅读的流畅&#xff0c;当前针对相同的代理任务按时间顺序进行梳理&#xff0c;涉及仅使用正负样本思想且优化目标一致的「基础」论文&#xff08;2018-2020&#xff09;&#xff0c;编码器均采用 ResNet。 文章目录 前言对比学习和代理任务&#xff08;Pretext task&#…

浪潮云启操作系统(InLinux)bcache缓存实践:理解OpenStack环境下虚拟机卷、Ceph OSD、bcache设备之间的映射关系

前言 在OpenStack平台上&#xff0c;采用bcache加速ceph分布式存储的方案被广泛用于企业和云环境。一方面&#xff0c;Ceph作为分布式存储系统&#xff0c;与虚拟机存储卷紧密结合&#xff0c;可以提供高可用和高性能的存储服务。另一方面&#xff0c;bcache作为混合存储方案&…

Java笔试06

在Java中&#xff0c;异常可以分为两大类&#xff1a;编译时异常&#xff08;编译时检查异常&#xff09;和运行时异常&#xff08;非编译时检查异常&#xff09;。 编译时异常&#xff08;Checked Exceptions&#xff09;是指在编译时期必须被捕获或声明抛出的异常。这些异常…

字节流写入文件

一、创建输出流对象表示的文件三种方式 方法一&#xff1a; FileOutputStream fos new FileOutputStream("fos.txt",true);//最简便方法二&#xff1a; FileOutputStream fos new FileOutputStream(new File("fos.txt"));方法三&#xff1b; File f ne…

Python | Leetcode Python题解之第502题IPO

题目&#xff1a; 题解&#xff1a; class Solution:def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:if w > max(capital):return w sum(nlargest(k, profits))n len(profits)curr 0arr [(capital[i], profits[i]…

HTML作业

作业 复现下面的图片 复现结果 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><form action"#"method"get"enctype"text/plain"><…

Java程序设计:spring boot(7)——数据访问操作

目录 1 查询操作 1.1 接口方法定义 1.2 映射文件配置 1.3 UserService 1.4 UserController 2 添加操作 2.1 接口方式定义 2.2 映射文件配置 2.3 添加 commons-lang3 依赖 2.4 AssertUtil ⼯具类 2.5 ParamsException ⾃定义异常 2.6 UserService 2.7 ResultInfo …

UDP传输协议Linux C语言实战

文章目录 1.UDP简介1.1特点1.2 UDP协议头部格式1.2.1 **UDP头部**&#xff1a;1.2.2 **头部意义**&#xff1a;1.2.3 **头部参数**&#xff1a; 1.3 UDP数据长度控制1.4 UDP协议建立框架 2. 函数介绍2.1 sendto函数2.2 recvform函数2.3 其他函数 3.实例3.1 通用结构体、IPV4结构…

算法的学习笔记—(牛客JZ50)

&#x1f600;前言 在处理字符串时&#xff0c;寻找第一个只出现一次的字符是一项常见的任务。本文将探讨几种有效的解法&#xff0c;包括使用 HashMap 和位集&#xff08;BitSet&#xff09;。 &#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 &#x1f970;第一个只出现…

软件分享丨豆包电脑端 AI 助手

豆包电脑端 AI 助手是由字节跳动推出&#xff0c;旨在为用户提供高效便捷的工作和学习体验。它能在工作、学习等场景中发挥重要作用&#xff0c;为用户提供智能辅助&#xff0c;下面简单介绍它的特点&#xff1a; 高效搜索&#xff1a;像优化后的百度&#xff0c;直接提问就能…

【本科毕业设计】基于单片机的智能家居防火防盗报警系统

基于单片机的智能家居防火防盗报警系统 相关资料链接下载摘要Abstract第1章 绪论1.1课题的背景1.2 研究的目的和意义 第2章 系统总体方案设计2.1 设计要求2.2 方案选择和论证2.2.1 单片机的选择2.2.2 显示方案的选择 第3章 系统硬件设计3.1 整体方案设计3.1.1 系统概述3.1.2 系…

C#通过异或(^)运算符制作二进制加密(C#实现加密)

快速了解异或运算符&#xff1a; 异或运算符在C#中用 “^” 来表示 口诀&#xff1a;相同取0&#xff0c;相异取1 简单加密解密winform示例&#xff1a; /// <summary>/// 异或运算符加密实现/// </summary>/// <param name"p_int_Num">初始值<…

生成式 AI 与向量搜索如何扩大零售运营:巨大潜力尚待挖掘

在竞争日益激烈的零售领域&#xff0c;行业领导者始终在探索革新客户体验和优化运营的新途径&#xff0c;而生成式 AI 和向量搜索在这方面将大有可为。从个性化营销到高效库存管理&#xff0c;二者在零售领域的诸多应用场景中都展现出变革性潜力&#xff0c;已成为保持行业领先…

云电脑的真实使用体验

最近这几年&#xff0c;关于云电脑的宣传越来越多。 小枣君之前曾经给大家介绍过云电脑&#xff08;链接&#xff09;。简单来说&#xff0c;它属于云计算的一个应用。通过在云端虚拟出一些虚拟电脑&#xff0c;然后让用户可以远程使用&#xff08;仍然需要借助本地电脑&#x…

使用爬虫爬取Python中文开发者社区基础教程的数据

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

CANoe_C#调用CDD和CAPL调用CDD方法对比

引言 在汽车电子系统的开发和测试中,CANoe作为一款强大的网络仿真工具,广泛应用于各种通信协议的模拟和验证。为了实现复杂的测试场景,开发者可以使用不同的编程语言和方法来调用CANoe的功能。其中,C#和CAPL(CANoe Programming Language)是两种常用的编程方式。本文将对…

Golang | Leetcode Golang题解之第498题对角线遍历

题目&#xff1a; 题解&#xff1a; func findDiagonalOrder(mat [][]int) []int {m, n : len(mat), len(mat[0])ans : make([]int, 0, m*n)for i : 0; i < mn-1; i {if i%2 1 {x : max(i-n1, 0)y : min(i, n-1)for x < m && y > 0 {ans append(ans, mat[x…

学习笔记——交换——STP(生成树)工作原理

三、工作原理 STP的基本原理是在一个有二层环路的网络中&#xff0c;交换机通过运行STP&#xff0c;自动生成一个没有环路的网络拓扑。这个无环网络拓扑也叫做STP树(STP Tree)&#xff0c;树节点为某些交换机&#xff0c;树枝为某些链路。当网络拓扑发生变化时&#xff0c;STP…

《汇编语言》第15章——实验15安装新的 int 9 中断例程

安装新的 int9 中断例程 安装一个新的 int 9 中断例程&#xff0c;功能:在 DOS 下&#xff0c;按下A键后&#xff0c;除非不再松开如果松开&#xff0c;就显示满屏幕的A&#xff0c;其他的键照常处理。 提示&#xff0c;按下一个键时产生的扫描码称为通码&#xff0c;松开一个…

云计算作业一hadoop:问题解决备忘

教程地址&#xff1a;https://blog.csdn.net/qq_53877854/article/details/142412784 修改网络配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33在root用户下编辑 静态ip地址配置后查看ip与配置不符 注意&#xff1a;确保在这之前已经在VMware的编辑>虚拟网络编…