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

C++设计模式单例模式(饿汉、懒汉模式)

文章目录

  • 单例模式
    • volatile关键字作用
    • std::atomic
    • std::memory_order_relaxed
    • GameConfig* tmp = m_instance.load(std::memory_order_relaxed);
    • std::memory_order_acquire
    • std::lock_guard\<std::mutex> lock(m_mutex);
    • std::memory_order_release和std::memory_order_relaxed的区别
    • m_instance.store(tmp, std::memory_order_relaxed);
    • 饿汉模式
    • 懒汉模式
    • 懒汉模式(进阶版)
    • 单例类UML图
    • 重点

单例模式

单例类除了只能创建一个该类对象外,在使用方面与普通类没什么区别

#include <atomic>
#include <mutex>// 游戏配置相关类
class GameConfig {private:GameConfig() {};GameConfig(const GameConfig& tmpobj);GameConfig& operator=(const GameConfig& tmpobj);~GameConfig() {};public:static GameConfig* getInstance() {GameConfig* tmp = m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);if(tmp == nullptr) {std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if(tmp == nullptr) {tmp = new GameConfig();std::atomic_thread_fence(std::memory_order_release);m_instance.store(tmp, std::memory_order_relaxed);}}return tmp;}private:static atomic<GameConfig*> m_instance;static std::mutex m_mutex;
};std::atomic<GameConfig*> GameConfig::m_instance;
std::mutex GameConfig::m_mutex;

volatile关键字作用

在这里插入图片描述

std::atomic

在这里插入图片描述

std::memory_order_relaxed

在这里插入图片描述

GameConfig* tmp = m_instance.load(std::memory_order_relaxed);

在这里插入图片描述

std::memory_order_acquire

在这里插入图片描述

std::lock_guard<std::mutex> lock(m_mutex);

在这里插入图片描述

std::memory_order_release和std::memory_order_relaxed的区别

在这里插入图片描述

m_instance.store(tmp, std::memory_order_relaxed);

在这里插入图片描述

饿汉模式

程序一执行,不管是否调用了getInstance成员函数,这个单件类对象就已经被创建了(对象创建将不受多线程问题困扰)

对饿汉式单例类对象的使用,应该在程序入口函数开始执行后,例如main主函数开始执行后

//饿汉式
class GameConfig
{//......
private:GameConfig() {};GameConfig(const GameConfig& tmpobj);GameConfig& operator=(const GameConfig& tmpobj);~GameConfig() {};
public:static GameConfig* getInstance(){return m_instance;}
private:static GameConfig* m_instance;	 //指向本类对象的指针private://手工释放单例类对象引入的GameConfig类中的嵌套类(垃圾回收)class Garbo {public:~Garbo() {if (GameConfig::m_instance != nullptr){delete GameConfig::m_instance;GameConfig::m_instance = nullptr;}}};private:static Garbo garboobj;
};GameConfig* GameConfig::m_instance = new GameConfig();//趁静态成员变量定义的时机直接初始化是被允许的,即便GameConfig构造函数用private修饰
GameConfig::Garbo GameConfig::garboobj;

懒汉模式

程序执行后该单例类对象并不存在,只有第一次调用getInstance成员函数时,该单例类对象才会被创建,这种方式能够更好的控制单例类的创建时机,以免过早加载可能导致对内存等资源不必要的消耗(加入类GameConfig非常庞大的话)

//懒汉式
//游戏配置相关类
class GameConfig
{//......
private:GameConfig() {};GameConfig(const GameConfig& tmpobj);GameConfig& operator = (const GameConfig& tmpobj);~GameConfig() {};
public:static GameConfig* getInstance(){//std::lock_guard<std::mutex> gcguard(my_mutex);if (m_instance == nullptr){//这里再加锁//std::lock_guard<std::mutex> gcguard(my_mutex);//if (m_instance == nullptr)//{m_instance = new GameConfig();static Garbo garboobj;//}}return m_instance;}public://要手工调用才能释放内存static void freeInstance(){if (m_instance != nullptr){delete GameConfig::m_instance;GameConfig::m_instance = nullptr;}}private://手工释放单件类对象引入的GameConfig类中的嵌套类(垃圾回收)class Garbo {public:~Garbo() {if (GameConfig::m_instance != nullptr){delete GameConfig::m_instance;GameConfig::m_instance = nullptr;}}};private:static GameConfig* m_instance; //指向本类对象的指针 static Garbo garboobj;
};GameConfig* GameConfig::m_instance = nullptr; //在类外,某个.cpp源文件的开头位置,为静态成员变量赋值(定义并赋值)
GameConfig::Garbo GameConfig::garboobj;

懒汉模式(进阶版)

//懒汉式
//游戏配置相关类 
class GameConfig
{
private:GameConfig() {};GameConfig(const GameConfig& tmpobj);GameConfig& operator = (const GameConfig& tmpobj);~GameConfig() {};
public:static GameConfig* getInstance(){GameConfig* tmp = m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);if (tmp == nullptr){std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if (tmp == nullptr){tmp = new GameConfig();static Garbo garboobj;std::atomic_thread_fence(std::memory_order_release);							m_instance.store(tmp, std::memory_order_relaxed);}}return tmp;}private://手工释放单件类对象引入的GameConfig类中的嵌套类(垃圾回收)class Garbo {public:~Garbo() {if (GameConfig::m_instance != nullptr){delete GameConfig::m_instance;GameConfig::m_instance = nullptr;}}};private:static atomic<GameConfig*> m_instance;static std::mutex m_mutex;
};std::atomic<GameConfig*> GameConfig::m_instance;
std::mutex GameConfig::m_mutex; 

单例类UML图

引入单例设计模式的实现意图:保证一个类仅有一个实例存在,同时提供能对该实例访问的全局方法(getInstance成员函数)

在这里插入图片描述

重点

不要在单例类的析构函数中引用其他单例类对象

之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!

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

相关文章:

  • Linux操作系统从入门到实战(十六)冯诺依曼体系结构,操作系统与系统调用和库函数概念
  • 【软件测试】BUG篇 — 详解
  • AI测试助手如何让Bug无处可藏
  • uni-app 网络请求终极选型:uni.request、axios、uni-network、alova 谁才是你的真命请求库?
  • Eclipse JSP/Servlet:深入解析与最佳实践
  • 繁花深处:花店建设的时代意义与多元应用—仙盟创梦IDE
  • 计算机视觉全景指南:从OpenCV预处理到YOLOv8实战,解锁多模态AI时代(第五章)
  • 【Docker进阶实战】从多容器编排到集群部署
  • [Linux]学习笔记系列 -- [arm][lib]
  • 13. 是否可以在static环境中访问非static变量
  • 如何在 Ubuntu 24.04 LTS Linux 上安装 MySQL 服务器
  • opencv颜色识别项目:识别水果
  • jmeter常规压测【读取csv文件】
  • Ubuntu 22.04 离线环境下完整安装 Anaconda、CUDA 12.1、NVIDIA 驱动及 cuDNN 8.9.3 教程
  • AI绘画:生成唐初秦叔宝全身像提示词
  • 安全运维工具链全解析
  • ELK分布式日志采集系统
  • 【系统分析师】软件需求工程——第11章学习笔记(上)
  • 旅行者1号无线电工作频段
  • 《解锁 C++ 起源与核心:命名空间用法 + 版本演进全知道》
  • 计算机网络:求地址块128.14.35.7/20中的相关信息
  • 《从零构建大语言模型》学习笔记4,注意力机制1
  • Redis如何实现一个分布式锁?
  • Redis主从复制和哨兵模式
  • nginx+lua+redis案例
  • Error: error:0308010C:digital envelope routines::unsupported at new Hash
  • node.js 学习笔记3 HTTP
  • #C语言——刷题攻略:牛客编程入门训练(八):分支控制(二)
  • Linux 虚拟机磁盘空间占满-全面清理方案
  • 【C++详解】红黑树规则讲解与模拟实现(内附红黑树插入操作思维导图)