- 单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例;
- 具体运用场景如:
- 设备管理器,系统中可能有多个设备,但是只有一个设备管理器,用于管理设备驱动;
- 数据池,用来缓存数据的数据结构,需要在一处写,多处读取或者多处写,多处读取;
- 全局只有一个实例:static 特性,同时禁止用户自己声明并定义实例(把构造函数设为 private)
- 线程安全
- 禁止赋值和拷贝
- 用户通过接口获取实例:使用 static 类成员函
1.1 有缺陷的懒汉式
- 线程安全的问题,当多线程获取单例时有可能引发竞态条件:第一个线程在if中判断 m_instance_ptr是空的,于是开始实例化单例;同时第2个线程也尝试获取单例,这个时候判断m_instance_ptr还是空的,于是也开始实例化单例;这样就会实例化出两个对象,这就是线程安全问题的由来; 解决办法:加锁
- 内存泄漏. 注意到类中只负责new出对象,却没有负责delete对象,因此只有构造函数被调用,析构函数却没有被调用;因此会导致内存泄漏。解决办法: 使用共享指针;
class Singleton
{
public:
~Singleton() {
cout<<"destructor called!"<< endl;
}
static Singleton* get_instance()
{
if(m_instance_ptr == nullptr)
{
m_instance_ptr = new Singleton;
}
return m_instance_ptr;
}
void use() const{
cout << "in use" << endl; }
private:
Singleton() {
cout << "constructor called!" << endl;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* m_instance_ptr;
};
Singleton* Singleton::m_instance_ptr = nullptr;
1.2 线程安全、内存安全的懒汉式单例(智能指针,锁)
class Singleton
{
typedef shared_ptr<Singleton> Ptr;
private:
Singleton()
{
cout << "constructor called!" << endl;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Ptr m_instance_ptr;
static mutex m_mutex;
public:
~Singleton()
{
cout << "destructor called!" << endl;
}
static Ptr get_instance()
{
if(m_instance_ptr == nullptr)
{
lock_guard<mutex>lk(m_mutex);
if(m_instance_ptr == nullptr)
{
m_instance_ptr = shared_ptr<Singleton>(new Singleton);
}
}
return m_instance_ptr;
}
void use() const
{
cout << "in use!" << endl;
}
};
Singleton::Ptr Singleton::m_instance_ptr = nullptr;
mutex Singleton::m_mutex;
1.3 最推荐的懒汉式单例(magic static)局部静态变量
class