单例模式
前言:
单例模式,顾名思义,只存在一个实例。官方定义:对于类的单例模式设计,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
单例模式在写法上有很多种,
有饿汉式(类加载的时候实例化),
懒汉式(类在使用的时候实例化),
保证线程安全的写法等。具体如下:(删除线表示不推荐使用)
① 饿汉式(静态常量)
② 饿汉式(静态代码块)
③ 懒汉式(线程不安全)
④ 懒汉式(线程安全,同步方法)
⑤ 懒汉式(线程安全,同步方法)
⑥ 双重检查double check
⑦ 静态内部类
⑧ 枚举
在IOC模式中,通常使用生命周期来实现单例,如services.AddSingleton();
懒汉式
懒汉式(Lazy-Initialization)的方法是直到使用时才实例化对象,
也就说直到调用get_instance() 方法的时候才 new 一个单例的对象。
好处是如果被调用就不会占用内存。
class Singleton{
private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
Singleton(Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Singleton* m_instance_ptr;
public:
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
static Singleton* get_instance(){
if(m_instance_ptr==nullptr){
m_instance_ptr = new Singleton;
}
return m_instance_ptr;
}
void use() const { std::cout << "in use" << std::endl; }
};
Singleton* Singleton::m_instance_ptr = nullptr;
Singleton* instance = Singleton::get_instance();
Singleton* instance_2 = Singleton::get_instance();
return 0;
- 线程安全的问题,当多线程获取单例时有可能引发竞态条件:第一个线程在if中判断
m_instance_ptr
是空的,于是开始实例化单例;同时第2个线程也尝试获取单例,这个时候判断m_instance_ptr
还是空的,于是也开始实例化单例;这样就会实例化出两个对象,这就是线程安全问题的由来; 解决办法:加锁 - 内存泄漏. 注意到类中只负责new出对象,却没有负责delete对象,因此只有构造函数被调用,析构函数却没有被调用;因此会导致内存泄漏。解决办法: 使用共享指针;
线程安全、内存安全的懒汉式单例 (智能指针,锁)
class Singleton{
public:
typedef std::shared_ptr<Singleton> Ptr;
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
Singleton(Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Ptr get_instance(){
// "double checked lock"
if(m_instance_ptr==nullptr){
std::lock_guard<std::mutex> lk(m_mutex);
if(m_instance_ptr == nullptr){
m_instance_ptr = std::shared_ptr<Singleton>(new Singleton);
}
}
return m_instance_ptr;
}
private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
static Ptr m_instance_ptr;
static std::mutex m_mutex;
};
Singleton::Ptr Singleton::m_instance_ptr = nullptr;
std::mutex Singleton::m_mutex;
Singleton::Ptr instance = Singleton::get_instance();
Singleton::Ptr instance2 = Singleton::get_instance();
最推荐的懒汉式单例——局部静态变量
class Singleton
{
public:
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
Singleton(const Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Singleton& get_instance(){
static Singleton instance;
return instance;
}
private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
};
饿汉式
class Singleton {
public:
static Singleton* getInstance()
{
return instance_;
};
private:
Singleton(){};
Singleton(const Singleton&){};
Singleton& operator=(const Singleton&){};
static Singleton* instance_;
};
Singleton* Singleton::instance_ = new Singleton();