C++设计模式单例模式(饿汉、懒汉模式)
对饿汉式单例类对象的使用,应该在程序入口函数开始执行后,例如main主函数开始执行后。
·
文章目录
- 单例模式
-
- 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成员函数)
重点
不要在单例类的析构函数中引用其他单例类对象
之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!
更多推荐
所有评论(0)