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

C++设计模式(单例模式)

一、介绍

1.动机

在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。

如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?

这应该是类设计者的责任,而不是使用者的责任。

 

2.定义

保证一个类仅有一个实例,并提供一个该实例的全局访问点。——GOF

 

3.结构图

 

4b56f1421b19494aac107f7cc9eb0b5d.jpeg

 

4.要点总结

  • Singleton模式中的实例构造器可以设置为protected以允许子类派生。
  • Singleton模式一般不支持拷贝构造函数和Clone接口,因为这有可能导致多个对象实例,与Singleton模式的初衷违背。
  • 如何实现多线程环境下安全的Singleton?注意对双检查锁的正确实现。

 

二、单例模式

1.概念

单例模式的核心在于类自身负责创建自己的唯一实例,并提供一个静态方法来获取这个实例,从而防止外部代码创建多个实例。

①单例模式的优点:

  • 节省资源,避免频繁创建和销毁对象。
  • 方便控制资源的使用。
  • 维护数据的一致性。

②单例模式的缺点:

  • 在多线程环境下,需要考虑线程安全问题。
  • 若使用锁机制可能会影响性能。

 

2.实现要点

单例模式的实现要点:

  • 私有化构造函数:防止在外部通过构造函数直接创建对象。
  • 禁用拷贝构造和赋值运算符:防止通过拷贝构造和赋值操作创建多个对象。
  • 静态变量:存储类的唯一实例。
  • 公有静态方法:提供一个全局访问点来获取这个实例。

单例模式分为饿汉式和懒汉式。

 

3.饿汉式

在程序启动时立即创建实例,因此本身是线程安全的。但无论是否使用实例,都会立即创建,可能导致资源浪费。

饿汉式单例:

class Singleton {
private:static Singleton* pSingleton;Singleton() {cout << "Singleton()" << endl;}~Singleton() {cout << "~Singleton()" << endl;}public:Singleton(const Singleton&) = delete;  //禁用拷贝构造函数Singleton& operator=(const Singleton&) = delete;  //禁用赋值运算符static Singleton* getInstance() {return pSingleton;}static void deleteInstance() {  //用于删除实例cout << "deleteInstance()" << endl;if (pSingleton) {delete pSingleton;pSingleton = nullptr;}}
};
Singleton* Singleton::pSingleton = new Singleton();
//直接创建实例

测试:

Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
cout << s1 << endl;
cout << s2 << endl;
Singleton::deleteInstance();

 

4.懒汉式

程序启动时实例并不存在,只有在需要使用时才会创建实例,这种方式要考虑线程安全的问题。

①使用静态局部变量实现懒汉式单例

class Singleton {
private:Singleton() {cout << "Singleton()" << endl;}~Singleton() {cout << "~Singleton()" << endl;}public:static Singleton* getInstance() {static Singleton instance;  //静态局部变量return &instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;};

静态局部变量存储在静态存储区,只在当前函数内有效,其它函数无法访问。

静态局部变量只在第一次调用时初始化,生命周期从第一次初始化开始,到程序结束为止。

 

②使用双检查锁实现懒汉式单例

class Singleton {
private:static mutex mtx;  //互斥锁static atomic<shared_ptr<Singleton>> pSingleton;  //原子智能指针Singleton() {cout << "Singleton()" << endl;}public:~Singleton() {  //设置为公有,智能指针要调用cout << "~Singleton()" << endl;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static shared_ptr<Singleton> getInstance() {shared_ptr<Singleton> ptr = pSingleton.load();  //读取if (!ptr) {  //第一次检查unique_lock<mutex> amtx(mtx);ptr = pSingleton.load();  //读取if (!ptr) {  //第二次检查ptr = shared_ptr<Singleton>(new Singleton);pSingleton.store(ptr);  //存储}}return ptr;}
};
mutex Singleton::mtx;
atomic<shared_ptr<Singleton>> Singleton::pSingleton = nullptr;

atomic的load和store成员函数用于以原子方式读取和存储原子变量。它们可以接受一个memory_order参数,该参数用于指定在内存模型中操作的内存顺序。如果不提供则会默认使用memory_order_seq_cst,这是最严格的内存顺序,它保证了读取操作的顺序性和内存可见性。

 

③使用call_once实现懒汉式单例

class Singleton {
private:static once_flag flag;  //用于标记static shared_ptr<Singleton> pSingleton;  //智能指针Singleton() {cout << "Singleton()" << endl;}public:~Singleton() {  //设置为公有,智能指针要调用cout << "~Singleton()" << endl;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static shared_ptr<Singleton> getInstance() {call_once(flag, [] {  //最多调用一次pSingleton = shared_ptr<Singleton>(new Singleton);});return pSingleton;}
};
once_flag Singleton::flag;
shared_ptr<Singleton> Singleton::pSingleton = nullptr;

call_once可以让函数或代码块在多线程环境中最多只被执行一次。

 

 

相关文章:

C++设计模式(单例模式)

一、介绍 1.动机 在软件系统中&#xff0c;经常有这样一些特殊的类&#xff0c;必须保证它们在系统中只存在一个实例&#xff0c;才能确保它们的逻辑正确性、以及良好的效率。 如何绕过常规的构造器&#xff0c;提供一种机制来保证一个类只有一个实例? 这应该是类设计者的…...

前端---CSS(部分用法)

HTML画页面--》这个页面就是页面上需要的元素罗列起来&#xff0c;但是页面效果很差&#xff0c;不好看&#xff0c;为了让页面好看&#xff0c;为了修饰页面---》CSS CSS的作用&#xff1a;修饰HTML页面 用了CSS之后&#xff0c;样式和元素本身做到了分离的效果。---》降低了代…...

2024年最新版Java八股文复习

最新版本Java八股文复习&#xff0c;每天更新一篇&#xff0c;博主正在持续努力更新中~~~ 一、Java基础篇1、怎么理解面向对象&#xff1f;简单说说封装、继承、多态三大特性&#xff1f;2、多态体现在哪几个方面&#xff1f;3、面向对象的设计原则你知道有哪些吗&#xff1f;4…...

计算机毕业设计Hadoop+Spark音乐推荐系统 音乐预测系统 音乐可视化大屏 音乐爬虫 HDFS hive数据仓库 机器学习 深度学习 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

MyBatis高级扩展

一、Mapper批量映射优化: 1.需求: Mapper 配置文件很多时&#xff0c;在全局配置文件中一个一个注册太麻烦&#xff0c;希望有一个办法能够一劳永逸 2.配置方式: Mybatis允许在指定Mapper映射文件时&#xff0c;只指定其所在的包: <mappers><package name"c…...

代码美学2:MATLAB制作渐变色

效果&#xff1a; %代码美学&#xff1a;MATLAB制作渐变色 % 创建一个10x10的矩阵来表示热力图的数据 data reshape(1:100, [10, 10]);% 创建热力图 figure; imagesc(data);% 设置颜色映射为“cool” colormap(cool);% 在热力图上添加边框 axis on; grid on;% 设置热力图的颜色…...

浅谈- “ 变量中 无符号 与 有符号 的 值转换 ”

在同一个表达式中&#xff0c;若同时出现 无符号变量 与 有符号变量 &#xff1a; 1、都转换为无符号类型&#xff1a;&#xff08;注&#xff1a;2^324294967296&#xff09;即unsigned int 的最大值 2、然后再运行表达式 实例&#xff1a; #include <stdio.h>char fun(…...

【AI绘画】Midjourney进阶:色调详解(上)

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney中的色彩控制为什么要控制色彩&#xff1f;为什么要在Midjourney中控制色彩&#xff1f; &#x1f4af;色调白色调淡色调明色调 &#x1f4af…...

代码管理之Gitlab

文章目录 Git基础概述场景本地修改未提交&#xff0c;拉取远程代码修改提交本地&#xff0c;远程已有新提交 GitIDEA引入Git拉取仓库代码最后位置 Git基础 概述 workspace 工作区&#xff1a;本地电脑上看到的目录&#xff1b; repository 本地仓库&#xff1a;就是工作区中隐…...

防御网络攻击的创新策略

关键要点 ● 了解各种类型的网络攻击对于组织加强防御至关重要。 ● 制定敏捷的网络安全策略可帮助企业快速应对新出现的威胁。 ● 跨行业协作和威胁情报共享可以增强整体安全性。 网络攻击威胁日益严重 网络攻击的数量和复杂程度急剧增加&#xff0c;对全球组织构成了重大…...

C++软件设计模式之组合模式概述

组合模式&#xff08;Composite Pattern&#xff09;是C软件设计模式中的一种&#xff0c;主要用于解决对象的层次结构问题。它允许你将对象组合成树形结构来表示“部分-整体”的层次结构&#xff0c;使得客户端可以统一地处理单个对象和组合对象。 主要用于解决的问题&#x…...

利用HTML5和CSS来实现一个漂亮的表格样式

利用HTML5和CSS来实现一个漂亮的表格样式 第一步&#xff1a;创建HTML结构第二步&#xff1a;添加CSS样式第三步&#xff1a;响应式设计第四步&#xff1a;加入交互效果 第一步&#xff1a;创建HTML结构 我们将用HTML创建一个基本的表格结构。代码如下&#xff1a; <!DOCT…...

Vivado程序固化到Flash

在上板调试FPGA时&#xff0c;通常使用JTAG接口下载程序到FPGA芯片中&#xff0c;FPGA本身是基于RAM工艺的器件&#xff0c;因此掉电后会丢失芯片内的程序&#xff0c;需要重新烧写程序。但是当程序需要投入使用时不能每一次都使用JTAG接口下载程序&#xff0c;一般FPGA的外围会…...

HCIA笔记3--TCP-UDP-交换机工作原理

1. tcp协议 可靠的连接 1.1 报文格式 1.2 三次握手 1.3 四次挥手 为什么TIME_WAIT需要2MSL的等待时间&#xff1f; &#xff08;a&#xff09; 为了实现可靠的关闭 &#xff08;b&#xff09;为了让过期的报文在网络上消失 对于(a), 假设host发给server的last ack丢了。 ser…...

计算机网络的功能

目录 信息交换 资源共享 分布式处理 可靠性增强 集中管理 信息交换 计算机网络最基本的功能之一是允许不同设备之间的数据通信。这包括电子邮件的发送和接收、即时消息的传递、文件传输等。通过网络&#xff0c;用户可以轻松地与全球各地的其他人进行沟通和协作。 信息交…...

Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)

14.1 命令请求的执行过程 一个命令请求从发送到获得回复的过程中&#xff0c;客户端和服务器都需要完成一系列操作。 14.1.1 发送命令请求 当用户在客户端中输入一个命令请求的时候&#xff0c;客户端会把这个命令请求转换为协议格式&#xff0c;然后通过连接到服务器的套接字…...

多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测

多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测 目录 多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现TCN-GRU时间卷积…...

windows安全中心,永久卸载工具分享

使用方法 2024Goby红队版工具分享&#xff0c;附2024年漏洞POC下载 下载链接&#xff1a; https://pan.quark.cn/s/4fc2712a2afc一路回车&#xff0c;选项Y即可 耐心等待几秒种&#xff0c;自动重启 此时打开windows安全中心&#xff0c;已经完全不能使用了&#xff0c;响应…...

《安富莱嵌入式周报》第346期:开源2GHz带宽,12bit分辨率,3.2Gsps采样率示波,开源固件安全分析器, 开源口袋电源,开源健康测量,FreeCAD

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频&#xff1a; https://www.bilibili.com/video/BV1TYBhYKECK/ 《安富莱嵌入式周报》第346期&#xff1a;开源2GHz带…...

Apache OFBiz xmlrpc XXE漏洞(CVE-2018-8033)

目录 1、漏洞描述 2、EXP下载地址 3、EXP利用 1、漏洞描述 Apache OFBiz是一套企业资源计划&#xff08;ERP&#xff09;系统。它提供了广泛的功能&#xff0c;包括销售、采购、库存、财务、CRM等。 Apache OFBiz还具有灵活的架构和可扩展性&#xff0c;允许用户根据业务需求…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...