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

【GeekBand】C++设计模式笔记12_Singleton_单件模式

1. “对象性能” 模式

  • 面向对象很好地解决了 “抽象” 的问题, 但是必不可免地要付出一定的代价。对于通常情况来讲,面向对象的成本大都可以忽略不计。但是某些情况,面向对象所带来的成本必须谨慎处理。
  • 典型模式
    • Singleton
    • Flyweight

2. Singleton 单件模式

2.1 动机(Motivation)

  • 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性以及良好的效率。
  • 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
  • 这应该是类设计者的责任,而不是使用者的责任。

2.2 模式定义

保证一个类仅有一个实例,并提供一个该实例的全局访问点
——《设计模式》GoF

2.3 实例代码

class Singleton {
private:// 将构造函数、拷贝构造函数设置成 private,不允许用户创建实例Singleton();Singleton(const Singleton& other);public:// 提供实例的全局访问点static Singleton* getInstance();private:// static 成员,唯一的实例static Singleton* m_instance;
};// static 成员初始化
Singleton* Singleton::m_instance = nullptr;/*
线程非安全版本,多线程环境下有可能创建出多个实例,
当线程A在执行完(1)、执行(2)之前,线程B抢到时间片,开始执行(1),这样线程A和B都可以创建出实例,
所以在多线程环境中需要加锁。
*/ 
Singleton* Singleton::getInstance() {if (m_instance == nullptr) {		// (1)m_instance = new Singleton();	// (2)}return m_instance;
}/*
线程安全版本,但锁的代价过高,
因为锁的粒度粗,进入函数后立马加锁,整个函数过程都持有锁,
一般m_instance是只读的,当m_instance创建完成后,各线程可以直接获取该实例,
该代码既有问题:当线程A持有锁时,线程B无法获取m_instance,必须等待线程A释放锁。
*/
Singleton* Singleton::getInstance() {Lock lock;if (m_instance == nullptr) {m_instance = new Singleton();}return m_instance;
}/*
双检查锁,但由于内存读写reorder不安全
reorder含义:编译器可能改变对象构造的顺序
常规对象构造分为3个步骤:a.分配空间;b.调用构造函数完成对象初始化;c.返回对象的指针;但编译器有时会改变这3个顺序,变成a.c.b。
这样代码就会出现问题:当m_instance未初始化时,线程A需要对m_instance进行实例化,若当线程A完成步骤a和c,而未完成b时,线程B调用该函数,由于此刻 m_instance != nullptr,会直接返回m_instance,但该实例尚未完成初始化,直接使用该实例会产生未定义行为。
(2)处的二次检查必不可少:当AB两个线程都通过(1)后开始抢锁,假设A抢到了锁,A对m_instance进行实例化,当线程A释放锁线程B获得锁后,如果没有(2)处的检查,线程B将再次对m_instance初始化,不符合单例模式设计原则。
*/
Singleton* Singleton::getInstance() { if (m_instance == nullptr) {	// (1)Lock lock;if (m_instance == nullptr) {		// (2),这里的二次检查必不可少m_instance = new Singleton();	// (3)}}return m_instance;
}// C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;Singleton* Singleton::getInstance() {Singleton* tmp = m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);	// 获取内存fenceif (tmp == nullptr) {std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton;std::atomic_thread_fence(std::memory_order_release);	// 释放内存fencem_instance.store(tmp, std::memory_order_relaxed);}}return tmp;
}

2.4 结构(Structure)

在这里插入图片描述

2.5 要点总结

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

相关文章:

【GeekBand】C++设计模式笔记12_Singleton_单件模式

1. “对象性能” 模式 面向对象很好地解决了 “抽象” 的问题&#xff0c; 但是必不可免地要付出一定的代价。对于通常情况来讲&#xff0c;面向对象的成本大都可以忽略不计。但是某些情况&#xff0c;面向对象所带来的成本必须谨慎处理。典型模式 SingletonFlyweight 2. Si…...

Pyhon基础数据结构(列表)【蓝桥杯】

a [1,2,3,4,5] a.reverse() print("a ",a) a.reverse() print("a ",a)# 列表 列表&#xff08;list&#xff09;有由一系列按照特定顺序排序的元素组成 列表是有顺序的&#xff0c;访问任何元素需要通过“下标访问” 所谓“下标”就是指元素在列表从左…...

Linux篇(权限管理命令)

目录 一、权限概述 1. 什么是权限 2. 为什么要设置权限 3. Linux中的权限类别 4. Linux中文件所有者 4.1. 所有者分类 4.2. 所有者的表示方法 属主权限 属组权限 其他权限 root用户&#xff08;超级管理员&#xff09; 二、普通权限管理 1. ls查看文件权限 2. 文件…...

深入理解 Spark 中的 Shuffle

Spark 的介绍与搭建&#xff1a;从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 Spark on YARN&#xff1a;Spark集群模式…...

leetcode-8-字符串转整数

题解: 代码:...

SQL注入注入方式(大纲)

SQL注入注入方式&#xff08;大纲&#xff09; 常规注入 通常没有任何过滤&#xff0c;直接把参数存放到SQL语句中。 宽字节注入 GBK 编码 两个字节表示一个字符ASCII 编码 一个字节表示一个字符MYSQL默认字节集是GBK等宽字节字符集 原理&#xff1a; 设置MySQL时错误配置…...

OpenCV基础(1)

1.图像读写与窗口显示 1.1.imread读取图像文件 Mat cv::imread(const string &filename,int flags IMREAD_COLOR); filename&#xff1a;要读取的图像文件名flags&#xff1a;读取模式&#xff0c;可以从枚举cv::ImreadModes中取值&#xff0c;默认取值是IMREAD_COLOR&am…...

【freertos】FreeRTOS信号量的介绍及使用

FreeRTOS信号量 一、概述二、PV原语三、函数接口1.创建一个计数信号量2.删除一个信号量3.信号量释放4.在中断释放信号量5.获取一个信号量&#xff0c;可以是二值信号量、计数信号量、互斥量。6.在中断获取一个信号量&#xff0c;可以是二值信号量、计数信号量7.创建一个二值信号…...

React Native 全栈开发实战班 - 图片加载与优化

在移动应用中&#xff0c;图片加载与优化 是提升用户体验和减少资源消耗的重要环节。图片加载不当可能导致应用卡顿、内存泄漏甚至崩溃。本章节将介绍 React Native 中常用的图片加载方法&#xff0c;包括 Image 组件的使用、第三方图片加载库&#xff08;如 react-native-fast…...

Golang云原生项目:—实现ping操作

熟悉报文结构 ICMP校验和算法&#xff1a; 报文内容&#xff0c;相邻两个字节拼接到一起组成一个16bit数&#xff0c;将这些数累加求和若长度为奇数&#xff0c;则将剩余一个字节&#xff0c;也累加求和得出总和之后&#xff0c;将和值的高16位与低16位不断求和&#xff0c;直…...

mysql如何查看当前事务的事务id

-- 开启一个事务&#xff0c;但不执行写操作 START TRANSACTION; -- 查询 InnoDB 事务信息 SELECT * FROM information_schema.innodb_trx;在 MySQL 的 MVCC (多版本并发控制) 中&#xff0c;事务 ID (Transaction ID) 是由 InnoDB 存储引擎分配的&#xff0c;它的分配机制与事…...

在linux里如何利用vim对比两个文档不同的行数

在Linux中&#xff0c;可以使用vimdiff命令来对比两个文档中不同的行。首先确保你的系统中安装了vim编辑器。 打开终端&#xff0c;使用以下命令来启动vimdiff&#xff1a; vimdiff file1 file2 这里file1和file2是你想要对比的两个文件的路径。 vimdiff会以并排方式打开两…...

深入解析Python中的逻辑回归:从入门到精通

引言 在数据科学领域&#xff0c;逻辑回归&#xff08;Logistic Regression&#xff09;是一个非常重要的算法&#xff0c;它不仅用于二分类问题&#xff0c;还可以通过一些技巧扩展到多分类问题。逻辑回归因其简单、高效且易于解释的特点&#xff0c;在金融、医疗、广告等多个…...

【数据库】mysql数据库迁移前应如何备份数据?

MySQL 数据库的备份是确保数据安全的重要措施之一。在进行数据库迁移之前&#xff0c;备份现有数据可以防止数据丢失或损坏。以下是一套详细的 MySQL 数据库备份步骤&#xff0c;适用于大多数情况。请注意&#xff0c;具体的命令和工具可能因 MySQL 版本的不同而有所差异。整个…...

C语言——鸡兔同笼问题

没注释的源代码 #include <stdio.h> #include <stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ int main(int argc, char *argv[]) { int tou 10; i…...

数据结构王道P234第二题

#include<iostream> using namespace std; int visit[MAxsize]; int color[MaxSize];//1表示红&#xff0c;2表示白&#xff1b; bool dfs(Graph G, int i){visit[i]1;ArcNode *p;bool flag1;for(pG.vertices[i].firsrarc; p ; pp->next){int jp->adjvex;if(!visi…...

层归一化和批归一化

层归一化是针对某一样本的所有特征&#xff0c;批归一化是针对所有样本的某一特征。 计算公式&#xff1a;&#xff08;当前值 - 均值&#xff09;/ 标准差。 作用&#xff1a;缓解梯度消失和梯度爆炸的问题&#xff0c;并提高网络的泛化性能。 为什么Transform和BERT中使用层归…...

Spring Cloud Gateway 网关

微服务网关 Spring Cloud Gateway https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories Spring Cloud 在版本 2020.0.0 开始&#xff0c;去除了 Zuul 网关的使用&#xff0c;改用 Spring Cloud Gateway 作为网关…...

LabVIEW中的UDP与TCP比较

在LabVIEW中&#xff0c;UDP和TCP可以用于不同的网络通信场景&#xff0c;开发者可以根据需求选择合适的协议。以下是结合LabVIEW开发时的一些比较和应用场景&#xff1a; 1.TCP在LabVIEW中的应用&#xff1a; 可靠性高的场景&#xff1a;当开发一个对数据传输的准确性和完整…...

半导体器件与物理篇3 P-N结

热平衡时的PN结 pn结的定义&#xff1a;由p型半导体和n型半导体接触形成的结 pn结的特性和关键变量包括&#xff1a;整流性&#xff08;即电流单向导通的特性&#xff09;、平衡费米能级&#xff08;费米能级 E F E_F EF​为常数, d E F d x 0 &#xff09;、内建电势 \frac…...

深入剖析String类的底层实现原理

嘿嘿,家人们,今天咱们来模拟实现string,好啦,废话不多讲,开干! 1:string.h 1.1:构造函数与拷贝构造函数 1.1.1:写法一 1.1.2:写法二(给缺省值) 1.2:赋值运算符重载与operatror[]获取元素 1.3:容量与迭代器 1.4:reserve与resize 1.5:清空与判断是否为空 1.6:push_back与…...

#其它:面试题

第一面试官提问如下&#xff1a; 1、自我介绍 2、根据项目提问&#xff1a;混合开发调取api的通讯方式 3、技术提问&#xff1a;如何隐藏div&#xff0c;但是div需要存在 使用 visibility 隐藏&#xff1a; 1.visibility: hidden2.display: none 3.opcity: 04、css塌陷问题…...

计算机视觉中的双边滤波:经典案例与Python代码解析

&#x1f31f; 计算机视觉中的双边滤波&#xff1a;经典案例与Python代码解析 &#x1f680; Hey小伙伴们&#xff01;今天我们要聊的是计算机视觉中的一个重要技术——双边滤波。双边滤波是一种非线性滤波方法&#xff0c;主要用于图像去噪和平滑&#xff0c;同时保留图像的边…...

【AI日记】24.11.17 看 GraphRAG 论文,了解月之暗面

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 核心工作 内容&#xff1a;看 GraphRAG 论文时间&#xff1a;4 小时评估&#xff1a;不错&#xff0c;继续 非核心工作 内容&#xff1a;了解国内大模型方向&#xff0c;重点了解了创业独角兽-月之暗面&…...

Front Panel Window Bounds 与 Front Panel Window Bounds 的区别与应用

在LabVIEW中&#xff0c;Front Panel Window Bounds 和 Front Panel WindowBounds 是两个不同的属性节点&#xff0c;用于描述前面板窗口的位置和大小。它们的区别主要体现在它们表示的是窗口的不同部分&#xff0c;具体如下&#xff1a; 1 Window Bounds&#xff1a;调整整个…...

比较TCP/IP和OSI/RM的区别

一、结构不同 1、OSI&#xff1a;OSI划分为7层结构&#xff1a;物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。 2、TCP/IP&#xff1a;TCP/IP划分为4层结构&#xff1a;应用层、传输层、互联网络层和主机-网络层。 二、性质不同 1、OSI&#xff1a;OSI是制定…...

【Java项目】基于SpringBoot的【招聘信息管理系统】

技术简介&#xff1a;系统软件架构选择B/S模式、SpringBoot框架、java技术和MySQL数据库等&#xff0c;总体功能模块运用自顶向下的分层思想。 系统简介&#xff1a;招聘信息管理系统的功能分为管理员&#xff0c;用户和企业三个部分&#xff0c;系统的主要功能包括首页、个人中…...

【论文笔记】LLaMA-VID: An Image is Worth 2 Tokens in Large Language Models

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: LLaMA-VID: An Image is W…...

使用Web Storage API实现客户端数据持久化

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Storage API实现客户端数据持久化 使用Web Storage API实现客户端数据持久化 使用Web Storage API实现客户端数据持久化…...

基于STM32F103的秒表设计-液晶显示

基于STM32F103的秒表设计-液晶显示 仿真软件: Proteus 8.17 编程软件: Keil 5 仿真实现: 在液晶1602上进行秒表显示,每100ms改变一次数值,一共三个按键,分为启动按键、暂停按键、复位按键。 电路介绍: 前面章节里已经和大家介绍了使用数码管设计的秒表,本次仿真将数…...