饿汉式
class Singleton {
private:
Singleton (){};
~Singleton (){};
static Singleton instance;
public:
static Singleton& GetInstance(){
return instance;
}
}
tip: 直接初始化一个实例对象,并提供唯一一个public方法线程安全,没有加锁,执行效率会提高,instance在类装载时就实例化,可能会产生垃圾对象浪费内存。
在main函数之前初始化,所以没有线程安全的问题,潜在问题在于no-local static对象(函数外的static对象)在不同编译单元中的初始化顺序是未定义的。
也即,static Singleton instance;和static Singleton& getInstance()二者的初始化顺序不确定,如果在初始化完成之前调用 getInstance() 方法会返回一个未定义的实例。
懒汉式
class Singleton {
private:
Singleton (){};
~Singleton (){};
static Singleton instance;
public:
static Singleton GetInstance(){
if(instance == NULL) {
instance = new Singleton();
}
return instance;
}
}
这种写法如果是static Singleton* instance,存在内存泄露的问题,有两种解决方法:使用智能指针或者使用静态的嵌套类对象
不支持多线程,没有加锁线程不安全。
懒汉式加锁
class Singleton {
private:
Singleton (){};
~Singleton (){};
static Singleton instance;
public:
static Singleton GetInstance(){
if(instance == NULL) {
Lock lock;
if(instance == NULL) {
instance = new Singleton();
}
}
return instance;
}
}
tip: 线程安全问题仅出现在第一次初始化(new)过程中,而在后面获取该实例的时候并不会遇到,也就没有必要再使用lock。
双检测锁很好地解决了这个问题,它通过加锁前检测是否已经初始化,避免了每次获取实例时都要首先获取锁资源。
还是有关于memory model的问题,if(instance == NULL)和instance = new Singleton()可能会没有正确的同步;利用atomic对象优化。
关于memory model和memory barrier需要好好研究一下。
最佳版本
class Singleton {
private:
Singleton (){};
~Singleton (){};
public:
static Singleton& GetInstance(){
static Singleton instance;
return instance;
}
}
在C++11标准下,一种更优雅的单例模式实现,使用函数内的 local static 对象,只有当第一次访问getInstance()方法时才创建实例。
参考 https://zhuanlan.zhihu.com/p/37469260