1、概述
单例模式是程序生命周期内,该类只有一个实例,并提供一个该实例访问点,适用于全局配置类、资源管理类等场景。
单实例模式特点:
1、构造函数私有
2、拷贝构造和赋值构造函数为私有
3、类有一个静态方法获取实例
2、静态局部变量(使用最广泛)
C++11标准中,要求局部静态变量初始化具有线程安全性
特性:如果变量在初始化时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束
class Singleton
{
public:static Singleton& GetInstance() {static Singleton instance;return instance;}
private:Singleton(){}~Singleton();Singleton(const Singleton&);Singleton& operator=(const Singleton&);
};
3、std::call_once方案
std::call_once是C++11引入的新特性,需要包含头文件<mutex>,确保函数在多线程环境下,只执行一次。
class Singleton {
public:~Singleton(){instance.reset();}static Singleton* getInstance() {std::call_once(single_flag, []() {instance.reset(new Singleton());});return instance.get();}Singleton(const Singleton&) = delete;void operator=(const Singleton&) = delete;private:Singleton() {};static std::once_flag single_flag;static std::unique_ptr<Singleton> instance;
};std::once_flag Singleton::single_flag;
std::unique_ptr<Singleton> Singleton::instance;
4、双检索方案(用的少)
// 加锁的懒汉式实现
class Singleton
{
public:// 获取单实例对象static Singleton *GetInstance();//释放单实例,进程退出时调用static void deleteInstance();// 打印实例地址void Print();private:// 将其构造和析构成为私有的, 禁止外部构造和析构Singleton();~Singleton();// 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值Singleton(const Singleton &signal);const Singleton &operator=(const Singleton &signal);private:// 唯一单实例对象指针static Singleton *m_SingleInstance;static std::mutex m_Mutex;
};//初始化静态成员变量
Singleton *Singleton::m_SingleInstance = nullptr;
std::mutex Singleton::m_Mutex;Singleton * Singleton::GetInstance()
{// 这里使用了两个 if 判断语句的技术称为双检锁;好处是,只有判断指针为空的时候才加锁,// 避免每次调用 GetInstance的方法都加锁,锁的开销毕竟还是有点大的。if (m_SingleInstance == nullptr){std::unique_lock<std::mutex> lock(m_Mutex); // 加锁if (m_SingleInstance == nullptr){volatile auto temp = new (std::nothrow) Singleton();m_SingleInstance = temp;}}return m_SingleInstance;
}void Singleton::deleteInstance()
{std::unique_lock<std::mutex> lock(m_Mutex); // 加锁if (m_SingleInstance){delete m_SingleInstance;m_SingleInstance = nullptr;}
}void Singleton::Print()
{std::cout << "我的实例内存地址是:" << this << std::endl;
}Singleton::Singleton()
{std::cout << "构造函数" << std::endl;
}Singleton::~Singleton()
{std::cout << "析构函数" << std::endl;
}
5、饿汉模式
该模式程序启动时,就将类实例化了。
这种模式有个注意事项:如果业务中有多个饿汉类,要考虑全局初始化顺序和依赖关系。
class Singleton {
private:static Singleton* instance; // 单例对象指针Singleton() {} // 私有构造函数public:static Singleton* GetInstance() {return instance; // 提供一个方法获取单例对象}
};// 在类外初始化静态成员
Singleton* Singleton::instance = new Singleton();
学习链接:https://github.com/0voice