C++设计模式创建型之单例模式
一、概述
单例模式也称单态模式,是一种创建型模式,用于创建只能产生一个对象实例的类。例如,项目中只存在一个声音管理系统、一个配置系统、一个文件管理系统、一个日志系统等,甚至如果吧整个Windows操作系统看成一个项目,那么其中只存在一个任务管理器窗口等。引入单例模式的实现意图:保证一个类仅有一个实例存在,同时提供能对该实例访问的全局方法。
二、单例模式分类
1、懒汉模式
1)代码示例
class CSingletonImpl
{
public:
static CSingletonImpl* GetInstance()
{
if (m_pInstance == nullptr)
{
m_pInstance = new CSingletonImpl;
}
return m_pInstance;
}
private:
CSingletonImpl(){};
~CSingletonImpl(){};
CSingletonImpl(const CSingletonImpl& the);
CSingletonImpl& operator=(const CSingletonImpl& other);
private:
static CSingletonImpl* m_pInstance;
};
CSingletonImpl*CSingletonImpl::m_pInstance = nullptr;
2)说明
单例模式为了防止多对象问题,将构造函数,析构函数,拷贝构造函数,赋值运算符函数设置为私有,同时设置公有唯一接口方法来创建对象,同时定义类静态指针。这是通用方法,那么会有什么问题呢?如果在单一线程中使用则没什么问题,但是在多线程中使用则可能导致问题,如果多个线程可能会因为操作系统时间片调度问题切换造成多对象产生,那么解决这个问题的方案就是对GetInstance()成员函数枷锁。
示例代码:
加入私有成员变量:static std::mutex m_mutex;
static CSingletonImpl* GetInstance()
{
m_mutex.lock();
if (m_pInstance == nullptr)
{
m_pInstance = new CSingletonImpl;
}
m_mutex.unlock();
return m_pInstance;
}
加入以上代码没有问题了吗?呵呵,还不行,虽然对接口函数加锁,从代码逻辑上没有问题,实现了线程安全,但是从执行效率上来说,是有大问题的。当程序运行中GetInstance()可能会被多个线程频繁调用,每次调用都会经历加锁解锁的过程,这样的话会严重影响程序执行效率,而且加锁机制仅仅对第一次创建对象有意义,对象一旦创建则变成只读对象,在多线程中,对只读对象的访问加锁不仅代价大,而且无意义。那么如何解决这个问题呢?那就是双重锁定机制,基于这种机制函数实现代码:
static CSingletonImpl* GetInstance()
{
if (m_pInstance == nullptr)
{
std::lock_guard<std::mutex> siguard(si_mutex);
if (m_pInstance == nullptr)
{
m_pInstance = new CSingletonImpl;
}
}
return m_pInstance;
}
上述双重锁定机制看起来比较完美,但实际上存在潜在的问题,内存访问重新排序导致双重锁定失效的问题,比较推荐的方法时C++11新标准的一些特性,示例代码如下:
#include <mutex>
#include <atomic>
//通过原子变量解决双重锁定底层问题(load,store)
class CSingletonImpl
{
public:
static CSingletonImpl* GetInstance()
{
CSingletonImpl* task = m_taskQ.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
if (task == nullptr)
{
std::lock_guard<std::m_mutex> lock(m_mutex);
task = m_taskQ.load(std::memory_order_relaxed);
if (task == nullptr)
{
task = new CSingletonImpl;
std::atomic_thread_fence(std::memory_order_release);
m_taskQ.store(task, std::memory_order_relaxed);
}
}
return task;
}
private:
CSingletonImpl(){};
~CSingletonImpl(){};
CSingletonImpl(const CSingletonImpl& the);
CSingletonImpl& operator=(const CSingletonImpl& other);
private:
static std::mutex m_mutex;
static std::atomic<CSingletonImpl*> m_taskQ;
};
std::mutex CSingletonImpl::m_mutex;
std::atomic<CSingletonImpl*> CSingletonImpl::m_taskQ;
2、饿汉模式
1)示例代码
class CSingletonImpl
{
public:
static CSingletonImpl* GetInstance()
{
return m_pInstance;
}
private:
CSingletonImpl(){};
~CSingletonImpl(){};
CSingletonImpl(const CSingletonImpl& the);
CSingletonImpl& operator=(const CSingletonImpl& other);
private:
static CSingletonImpl* m_pInstance;
};
CSingletonImpl*CSingletonImpl::m_pInstance = new CSingletonImpl();
2)说明
此类模式可称为饿汉式--------程序一执行不管是否调用了GetInstance()成员函数,这个单例类对象就已经被创建了。在饿汉式单例类代码的实现必须要注意,如果一个项目中有多个.cpp源文件,而且这些源文件中包含对全局变量的初始化代码,例如某个.cpp中可能存在如下代码:
int g_test = CSingletonImpl::GetInstance()->m_i; //m_i是int类型变量
那么这样的代码是不安全的,因为多个源文件中全局变量的初始化顺序是不确定的,很可能造成GetInstance()函数返回是nullptr,此时去访问m_i成员变量肯定会导致程序执行异常。所以,对饿汉式单例类对象的使用,应该在程序入口函数开始执行后,例如main函数后。
注意:函数第一次执行时被初始化的静态变量与通过编译器常量进行初始化的基本类型静态变量这两种情况,不要再单例类的析构函数中引用其他单例类对象。
相关文章:
C++设计模式创建型之单例模式
一、概述 单例模式也称单态模式,是一种创建型模式,用于创建只能产生一个对象实例的类。例如,项目中只存在一个声音管理系统、一个配置系统、一个文件管理系统、一个日志系统等,甚至如果吧整个Windows操作系统看成一个项目…...
杂记 | 记录一次使用Docker安装gitlab-ce的过程(含配置交换内存)
文章目录 01 准备工作02 (可选)配置交换内存03 编辑docker-compose.yml04 启动并修改配置05 nginx反向代理06 (可选)修改配置文件07 访问并登录 01 准备工作 最近想自建一个gitlab服务来保存自己的项目,于是找到gitla…...
MyBatis@Param注解的用法
一、前言 本人在学习mybatis的过程中遇到的一个让人不爽的bug,在查找了些相关的资料后得以解决,遂记录。 二、报错及解决 mapper中有一方法: Select("select * from emp " "where name like concat(%, #{name}, %) "…...
Shader 编程:GLSL 重要的内置函数
该原创文章首发于微信公众号:字节流动 未经作者(微信ID:Byte-Flow)允许,禁止转载 前面发了一些关于 Shader 编程的文章,有读者反馈太碎片化了,希望这里能整理出来一个系列,方便系统的…...
浏览器同源策略
浏览器同源策略 同源策略:是一个重要的浏览器的安全策略,用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互 它能帮助阻隔恶意文档,减少可能被攻击的媒介 例如:被钓鱼网站收集信息,使用ajax发起…...
GD32F103的EXTI中断和EXTI事件
GD32F103的EXTI可以产生中断,也产生事件信号。 GD32F03的EXTI触发源: 1、I/O管脚的16根线; 2、内部模块的4根线(包括LVD、RTC闹钟、USB唤醒、以太网唤醒)。 通过配置GPIO模块的AFIO_EXTISSx寄存器,所有的GPIO管脚都可以被选作EXTI的触发源…...
了解 spring MVC + 使用spring MVC - springboot
前言 本篇介绍什么是spring MVC ,如何使用spring MVC,了解如何连接客户端与后端,如何从前端获取各种参数;如有错误,请在评论区指正,让我们一起交流,共同进步! 文章目录 前言1. 什么…...
C#中的Invoke
在 C# 中,Invoke() 是一个用于调用方法的方法,它能够在运行时动态地调用一个方法。 Invoke() 方法的使用方式有两种: 通过 MethodInfo 对象调用: using System.Reflection;namespace ConsoleApp_Invoke {public class Program{…...
Hive终端命令行打印很多日志时,如何设置日志级别
示例:use test; 切换到test数据库时,输出很多日志信息不方便看结果,如下图。 解决方法: 退出hive命令行界面(ctrlC)执行“vi /usr/local/apache-hive-3.1.2-bin/conf/log4j.properties”命令,创…...
Android的PopupWindow(详细版)
经典好文推荐,通过阅读本文,您将收获以下知识点: 一、PopupWindow简介 二、PopupWindow 的使用方法 三、底部PopupWindow的实现 四、参考文献 一、PopupWindow简介 在学习PopupWindow之前,我们先了解一下PopupWindow的继承关系。 PopupWindow继承关系如下: java.lang.Obje…...
Navicat远程连接Linux的MySQL
打开Linux终端,进入root权限,用vim打开MySQL的配置文件 vim /etc/mysql/mysql.conf.d/mysqld.cnf将bind-address的值改为0.0.0.0 进入MySQL mysql -u root -p 将root用户改为允许远程登录 update user set host % where user root; 创建用户 CRE…...
Spring IOC
◆ 传统Javaweb开发的困惑 ◆ IoC、DI和AOP思想提出 ◆ Spring框架的诞生 Spring | Home IOC控制反转:BeanFactory 快速入门 package com.xiaolin.service.Impl;import com.xiaolin.dao.UserDao; import com.xiaolin.service.UserService;public class UserServic…...
华为OD机试真题【上班之路】
1、题目描述 【上班之路】 Jungle 生活在美丽的蓝鲸城,大马路都是方方正正,但是每天马路的封闭情况都不一样。 地图由以下元素组成: 1)”.” — 空地,可以达到; 2)”*” — 路障,不可达到; 3&a…...
【linux源码学习】【实验篇】使用bochs运行linux0.11系统(搭建一个自己的工作站)
目录 背景资源获取bochs环境搭建windowsbochs环境搭建linux声明 背景 最近看赵炯老师的《linux内核完全注释》,然后在最后一个习题里面看到使用bochs跑一下0.11的内核代码,本来觉得很难,但是如果做过一遍就会发现其实很简单,这个…...
java+springboot+mysql个人日记管理系统
项目介绍: 使用javaspringbootmysql开发的个人日记管理系统,系统包含超级管理员、管理员、用户角色,功能如下: 超级管理员:管理员管理;用户管理;反馈管理;系统公告;个人…...
旋转图像 LeetCode热题100
题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 思路 利用矩阵性质,先反转矩阵的每一列元素,再把…...
Vue3 element-plus表单嵌套表格实现动态表单验证
Vue3结合element-plus表单项可以动态添加/删除 部分效果图如下: 另表格有添加和删除按钮,点击提交进行表单验证。 首先data格式必须是对象包裹数组 import { ref, reactive } from vue; import { FormInstance } from element-plus const froms re…...
VSCode插件Todo Tree的使用
在VSCode中安装插件Todo Tree。按下快捷键ctrlshiftP,输入setting.jspn,选择相应的配置范围,我们选择的是用户配置 Open User Settings(JSON),将以下代码插入其中。 //todo-tree 标签配置从这里开始 标签兼容大小写字母(很好的功…...
无人驾驶实战-第五课(动态环境感知与3D检测算法)
激光雷达的分类: 机械式Lidar:TOF、N个独立激光单元、旋转产生360度视场 MEMS式Lidar:不旋转 激光雷达的输出是点云,点云数据特点: 简单:x y z i (i为信号强度) 稀疏:7%&…...
Tomcat 的内存配置
修改 Tomcat 的内存配置,你需要调整 Tomcat 的 Java 虚拟机(JVM)参数。具体来说,你需要修改 catalina.sh(Linux/macOS)或 catalina.bat(Windows)脚本中的 JAVA_OPTS 变量。以下是一般…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
