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成员函数)
重点
不要在单例类的析构函数中引用其他单例类对象
之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!