创建型模式——单例(singleton)
1. 模式说明
单例模式保证类只有一个实例;创建一个对象,当你创建第二个对象的时候,此时你获取到的是已经创建过的对象,而不是一个新的对象;
1.1 使用场景
共享资源的访问权限;任务的管理类;数据库的操作等;
1.2 要素
- 私有化类的构造函数;
- 使用类的私有静态指针变量指向类的唯一实例
- 公有静态方法获取该实例;
1.3 类型
- 懒汉模式
- 饿汉模式
2. 懒汉模式
单例实例在第一次被使用时才进行初始化,延迟初始化
2.1 基本
示例
/** @brief : design patterns singleton* @author : your name* @compile : g++ -g singleton_main.cc -o d -std=c++11* @date : 2023/04/18* @lastEditorDate: */#include <iostream>
#include <string>//懒汉模式
class Singleton
{
public:static Singleton* getSingletonInstance() //访问函数{if(instance == nullptr){instance = new Singleton;}return instance;}public:void addCount() {m_count++;}int32_t getCount() {return m_count;}private:static Singleton* instance; //静态指针变量Singleton(){} //私有化类的构造函数int32_t m_count{0};
};Singleton* Singleton::instance = nullptr; //静态成员类外初始化int main(int argc, char* argv[])
{Singleton* single_0 = Singleton::getSingletonInstance();single_0->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl<<std::endl;Singleton* single_1 = Singleton::getSingletonInstance();single_1->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl;std::cout<<"single_1 value is: "<<single_1->getCount()<<std::endl<<std::endl; return 0;
}
输出
single_0 value is: 1single_0 value is: 2
single_1 value is: 2
2.2 线程安全
2.1中的示例是线程不安全的,假如有多个线程同时调用getSingletonInstance(),此时检测到instance是nullptr,就会导致单例的崩溃,造成内存泄漏;
通过加锁来实现
示例
/** @brief : design patterns singleton* @author : your name* @compile : g++ -g singleton_main.cc -o d -std=c++11* @date : 2023/04/18* @lastEditorDate: */#include <iostream>
#include <string>
#include <mutex>//懒汉模式
std::mutex mtx; //全局的锁
class Singleton
{
public:static Singleton* getSingletonInstance() //访问函数{if(instance == nullptr){std::lock_guard<std::mutex> guard(mtx); if(instance == nullptr){instance = new Singleton;} }return instance;}public:void addCount() {m_count++;}int32_t getCount() {return m_count;}private: static Singleton* instance; //静态指针变量Singleton(){} //私有化类的构造函数int32_t m_count{0};
};
Singleton* Singleton::instance = nullptr; //静态成员类外初始化int main(int argc, char* argv[])
{Singleton* single_0 = Singleton::getSingletonInstance();single_0->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl<<std::endl;Singleton* single_1 = Singleton::getSingletonInstance();single_1->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl;std::cout<<"single_1 value is: "<<single_1->getCount()<<std::endl<<std::endl; return 0;
}
输出
single_0 value is: 1single_0 value is: 2
single_1 value is: 2
使用 c++11 中局部静态变量是线程安全的性质
示例
/** @brief : design patterns singleton* @author : your name* @compile : g++ -g singleton_main.cc -o d -std=c++11* @date : 2023/04/18* @lastEditorDate: */#include <iostream>
#include <string>
#include <mutex>//懒汉模式
class Singleton
{
public:static Singleton* getSingletonInstance() //访问函数{static Singleton instance; //静态指针变量return &instance;}public:void addCount() {m_count++;}int32_t getCount() {return m_count;}private: Singleton(){} //私有化类的构造函数int32_t m_count{0};
};int main(int argc, char* argv[])
{Singleton* single_0 = Singleton::getSingletonInstance();single_0->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl<<std::endl;Singleton* single_1 = Singleton::getSingletonInstance();single_1->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl;std::cout<<"single_1 value is: "<<single_1->getCount()<<std::endl<<std::endl; return 0;
}
输出
single_0 value is: 1single_0 value is: 2
single_1 value is: 2
3. 饿汉模式
指单例实例在程序运行时被立即执行初始化
示例
/** @brief : design patterns singleton* @author : your name* @compile : g++ -g singleton_main.cc -o d -std=c++11* @date : 2023/04/18* @lastEditorDate: */#include <iostream>
#include <string>
#include <mutex>//饿汉模式
class Singleton
{
public:static Singleton* getSingletonInstance() //访问函数{ return instance;}public:void addCount() {m_count++;}int32_t getCount() {return m_count;}private:static Singleton* instance; //静态指针变量Singleton(){} //私有化类的构造函数int32_t m_count{0};
};Singleton* Singleton::instance = new Singleton; //静态成员类外初始化int main(int argc, char* argv[])
{Singleton* single_0 = Singleton::getSingletonInstance();single_0->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl<<std::endl;Singleton* single_1 = Singleton::getSingletonInstance();single_1->addCount();std::cout<<"single_0 value is: "<<single_0->getCount()<<std::endl;std::cout<<"single_1 value is: "<<single_1->getCount()<<std::endl<<std::endl; return 0;
}
输出
single_0 value is: 1single_0 value is: 2
single_1 value is: 2
4. 在开发过程中的使用
在项目的使用过程中,可以将单例设计成为类模板;这样其它类在设计的时候不用考虑,是否需要将其设计成为单例;
其它类如果需要单例属性,只需要通过单例模板对其进行赋能即可;
示例
/** @brief : design patterns singleton* @author : your name* @compile : g++ -g singleton_main.cc -o d -std=c++11* @date : 2023/04/18* @lastEditorDate: */#include <iostream>
#include <string>
#include <mutex>template<class T>
class Singleton
{
public:static T* getSingletonInstance() //访问函数{static T instance; //静态指针变量return &instance;}
private: Singleton(){} //私有化类的构造函数
};class C1
{
public:void addCount() {m_count++;}int32_t getCount() {return m_count;} private: int32_t m_count{0};
};int main(int argc, char* argv[])
{auto re1 = Singleton<C1>::getSingletonInstance();re1->addCount();std::cout<<"re1->getCount() value is: "<<re1->getCount()<<std::endl;auto re2 = Singleton<C1>::getSingletonInstance();re2->addCount();std::cout<<"re1->getCount() value is: "<<re1->getCount()<<std::endl;std::cout<<"re2->getCount() value is: "<<re2->getCount()<<std::endl;return 0;
}
输出
re1->getCount() value is: 1
re1->getCount() value is: 2
re2->getCount() value is: 2
相关文章:
创建型模式——单例(singleton)
1. 模式说明 单例模式保证类只有一个实例;创建一个对象,当你创建第二个对象的时候,此时你获取到的是已经创建过的对象,而不是一个新的对象; 1.1 使用场景 共享资源的访问权限;任务的管理类;数…...
算法:迷宫问题
描述 定义一个二维数组 N*M ,如 5 5 数组下所示: int maze[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或…...
聊聊并发编程的12种业务场景
前言 并发编程是一项非常重要的技术,无论在面试,还是工作中出现的频率非常高。 并发编程说白了就是多线程编程,但多线程一定比单线程效率更高? 答:不一定,要看具体业务场景。 毕竟如果使用了多线程&…...
MySQL执行顺序
MySQL执行顺序 MySQL语句的执行顺序也是在面试过程中经常问到的问题,并且熟悉执行顺序也有助于SQL语句的编写。 SELECT FROM JOIN ON WHERE GROUP BY HAVING ORDER BY LIMIT执行顺序如下: FROM ON JOIN WHERE GROUP BY # (开始使用别名) SUM # SUM等…...
引领真无线耳机未来趋势,NANK南卡OE骨传导真无线耳机惊艳亮相
传统的蓝牙耳机存在很多问题,例如续航时间短、长期佩戴耳朵会不舒服,甚至影响听力等等。为了解决这些问题,在骨传导领域深耕十多年的南卡品牌推出了这款真无线骨传导耳机——NANK南卡 OE。 NANK南卡OE即将正式上线,这一消息一经宣…...
5款写作神器,帮助你写出5w+爆款文案,好用到哭
我不允许还有文案小白、新手博主不知道这5款写作利器! 每次一写文案就头秃的新媒体工作者,赶紧看过来吧!这5款好用到爆的写作神器,喝一杯咖啡的时间就能完成写作。 我和同事都是用它们,出了很多的爆款,现…...
相交链表问题
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后&…...
[ubuntu] ax200网卡虚接,导致系统根目录占满而无法进入系统的奇葩问题
20230508,我像往常一样,打开电脑发现根目录满了,报警了,所以按照网上的教程,清理了一下根目录的文件,没想到背后是网卡问题… 文章目录 1.进入终端模式2.查看占用情况3.清理系统log文件3.1 清理/var/log/syslog3.2 清…...
本地字体库的引入方法
本地字体库是指在计算机系统中存储的一组字体文件,通常包含多种字体格式,如TTF、OTF、WOFF等。引入本地字体库可以让用户在使用计算机时可以选择不同的字体,从而提高用户的使用体验。 本地字体库的引入方式有多种,其中比较常用的是…...
7种优秀的导航菜单设计总结
导航是应用程序界面中最常见的模块之一,在链接应用程序中起着每个页面的作用。 不同的设计需求和业务目标决定了导航的设计因品而异,移动设备的尺寸远小于计算机。因此,在设计移动终端导航时,应考虑更全面,以确保简单…...
Problem E. 矩阵游戏 (2023年ccpc河南省赛)
原题链接: https://codeforces.com/gym/104354 题意: 有一个n*m的矩阵,只有三种字符:0,1和?。从[1,1]走到[n,m],每次只能向下走或者向下走。当走到1的时候得一分,走到0的时候不得分,走到?的时候可以将他…...
数字孪生模型构建理论及应用
源自:计算机集成制造系统 作者:陶飞 张贺 戚庆林 徐 俊 孙铮 胡天亮 刘晓军 刘庭煜 关俊涛 陈畅宇 孟凡伟 张辰源 李志远 魏永利 朱铭浩 肖斌 摘 要 数字孪生作为实现数字化转型和促进智能化升级的重要使能途径,一直备受各…...
Vue面试题:30道含答案和代码示例的练习题
Vue中的双向数据绑定是怎么实现的? 双向数据绑定通过使用v-model指令实现。v-model指令会在表单元素上创建一个监听器,在用户输入时实时更新Vue实例的数据,并且在Vue实例数据变化时更新表单元素的值。 如何在Vue中定义一个方法?…...
2023-05-09 LeetCode每日一题(有效时间的数目)
2023-05-09每日一题 一、题目编号 2437. 有效时间的数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 5 的字符串 time ,表示一个电子时钟当前的时间,格式为 “hh:mm” 。最早 可能的时间是 “00:00” ,最晚 可能的时间…...
第三节课 Linux文件权限
目录 文件属性详解 权限修改 文件所有者与属组修改 文件默认权限修改 Linux是多人多任务的操作系统,因此可能常常会有多人使用一台机器, 为了考虑每个人的隐私、方便用户合作,每个文件都有三类用户,权限是基于这三类用户设定的…...
开发STC89C51系列单片机需要的单片机技术
端口操作:控制单片机的输入输出端口,与外界进行通信。中断优先级:当多个中断同时发生时,确定哪个中断优先级更高,优先响应。时钟模块:控制单片机的时钟,可以精确计时。PWM技术:实现模…...
分布式键值存储是什么?(分布式键值存储大值)
文章目录 什么是分布式键值存储?分布式键值存储“大值”指什么? 什么是分布式键值存储? 分布式键值存储是一种分布式数据存储系统,它将数据存储为键值对的形式,并将这些键值对分散在多个节点上。每个节点都可以独立地…...
多线程(线程同步和互斥+线程安全+条件变量)
线程互斥 线程互斥: 任何时刻,保证只有一个执行流进入临界区访问临界资源,通常对临界资源起到保护作用 相关概念 临界资源: 一次仅允许一个进程使用的共享资源临界区: 每个线程内部,访问临界资源的代码&am…...
Flutter学习——开发Flutter需要的技能
第二章 Flutter开发所需要掌握的知识 文章目录 第二章 Flutter开发所需要掌握的知识前言一、开发语言Dart语言Android/Ios知识 二、组件学习三、调试与性能优化总结 前言 上一章,介绍了Flutter的来源和平台支持及特点,这一章,来梳理一下学习…...
SPSS如何进行因子分析和主成分分析之案例实训?
文章目录 0.引言1.因子分析2.主成分分析 0.引言 因科研等多场景需要进行数据统计分析,笔者对SPSS进行了学习,本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结,本文对因子分析和主成分分析进行阐述。 1.因…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
背包问题双雄:01 背包与完全背包详解(Java 实现)
一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...
