当前位置: 首页 > 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可以让函数或代码块在多线程环境中最多只被执行一次。

 

 

http://www.lryc.cn/news/491964.html

相关文章:

  • 前端---CSS(部分用法)
  • 2024年最新版Java八股文复习
  • 计算机毕业设计Hadoop+Spark音乐推荐系统 音乐预测系统 音乐可视化大屏 音乐爬虫 HDFS hive数据仓库 机器学习 深度学习 大数据毕业设计
  • MyBatis高级扩展
  • 代码美学2:MATLAB制作渐变色
  • 浅谈- “ 变量中 无符号 与 有符号 的 值转换 ”
  • 【AI绘画】Midjourney进阶:色调详解(上)
  • 代码管理之Gitlab
  • 防御网络攻击的创新策略
  • C++软件设计模式之组合模式概述
  • 利用HTML5和CSS来实现一个漂亮的表格样式
  • Vivado程序固化到Flash
  • HCIA笔记3--TCP-UDP-交换机工作原理
  • 计算机网络的功能
  • Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)
  • 多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测
  • windows安全中心,永久卸载工具分享
  • 《安富莱嵌入式周报》第346期:开源2GHz带宽,12bit分辨率,3.2Gsps采样率示波,开源固件安全分析器, 开源口袋电源,开源健康测量,FreeCAD
  • Apache OFBiz xmlrpc XXE漏洞(CVE-2018-8033)
  • 【论文复现】融入模糊规则的宽度神经网络结构
  • sql server 获取当前日期的时间戳
  • LLM PPT Translator
  • 铲屎官进,2024年宠物空气净化器十大排行,看看哪款吸毛最佳?
  • python 中常用的定积分求解方法
  • 音视频相关的一些基本概念
  • pikachu文件上传漏洞通关详解
  • 【拥抱AI】向量数据库有哪些常见的检索算法?
  • Webpack前端工程化进阶系列(二) —— HMR热模块更新(图文+代码)
  • 【RAG 项目实战 07】替换 ConversationalRetrievalChain(单轮问答)
  • godot游戏引擎_瓦片集和瓦片地图介绍