单例模式
介绍
单例模式可以确保全局只有一个实例对象,适用于共享资源访问、配置信息管理、日志记录等,使用时应谨慎考虑,滥用单例模式可能会导致全局状态的复杂性增加,增加代码的耦合性,使测试和调试变得困难。
创建
使用函数**GetInstance()**在任何cpp文件中调用时会检查m_instance是否为空。检查时使用双重锁机制,避免多线程出现问题。首次调用会生成实例对象的指针。再次调用只会获取到首次调用生成的指针的地址,即无论调用多少次只会有一个实例存在,可以在多个cpp文件中实现数据共享。
双重锁意义
双重锁分别指的是两次 if (m_instance == nullptr) 是否为空判断。
第一次空值判断是为了提升函数效率,如果单例对象不为空,则直接范围,不用在走后面的加锁等操作。
第二次加锁之后的非空判断是为了防止多线程访问时可能出现的多次初始化。
释放
常见的释放方式:
- 定义显式的释放函数,在程序退出前显式调用
- 析构函数释放,某些语言可以使用。但在C++中析构函数调用需要我们主动调用delete函数。在释放时需要额外检查当前单例对象还有多少引用,只有当引用为0时才可以释放空间
- 使用一个管理类统一管理
本文使用的是一个声明周期和单例对象一样的静态变量m_release来进行单例对象释放,这样做外部不用管单例对象的是否还有其他使用,不用显示调用。当程序关闭时自动会销毁m_release变量,m_release变量销毁时才会调用一次析构函数用于释放单例资源。
示例
SingletonServer.h文件
//可用于全局的单例服务
class SingletonServer
{
private:
SingletonServer();
public:
static SingletonServer* GetInstance();//获取单例对象
void Test(){std::cout<<"hello world"<<std::endl;}
private:
static SingletonServer* m_instance;//单例对象
static std::mutex* m_instance_lock;//单例锁
//垃圾回收,用于指针内存释放
class Release
{
public:
~Release() {
if (SingletonServer::m_instance != nullptr) {
delete SingletonServer::m_instance;
}
delete m_instance_lock;
}
};
static Release m_release;
};
SingletonServer.cpp文件
SingletonServer* SingletonServer::m_instance = nullptr;
SingletonServer::Release SingletonServer::m_release = Release();
std::mutex* SingletonServer::m_instance_lock = new std::mutex();
//获取单例服务的指针对象,采用双重锁机制,仅第一次调用会实例化对象
SingletonServer* SingletonServer::GetInstance() {
if (m_instance == nullptr) {
std::lock_guard<std::mutex> lock(*m_instance_lock);
if (m_instance == nullptr) {
m_instance = new SingletonServer();
}
}
return m_instance;
}
SingletonServer::SingletonServer()
{
}
使用示例:
SingletonServer *m_server;
m_server= SingletonServer ::GetInstance();
m_server.Test();