Singleton模式
singleton模式是GOF23中模式中比较简单的一种,也是可以笔试手写不多的的模式之一。笔试中经常遇到
- 动机:保证特殊类在系统中只存在一个实例,从而确保逻辑正确性和效率
- 定义: 保证一个类仅有一个实例,并提供一个该实例的全局访问点
- UML类图如下
其实现的要点:
- 一般不要支持拷贝构造函数和clone接口;构造函数一般设为 private(有时候可为protected)
- 注意单线程,多线程的单锁或 双检查锁的正确实现
实现1 线程非安全版本
class Singleton{
private:
Singleton();
Singleton(const Singleton& other);
public:
static Singleton* getInstance();
static Singleton* m_instance;
};
Singleton* Singleton::m_instance=nullptr;
//线程非安全版本,可能出错
Singleton* Singleton::getInstance() {
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}
多线程版本,加锁实现,注意加锁的位置
//线程安全版本,但锁的代价过高
Singleton* Singleton::getInstance() {
Lock lock;
if (m_instance == nullptr) {// 可能两次获得if
// 若锁在这里,还是出错
m_instance = new Singleton();
}
return m_instance;
}
采用双检查锁(面试使用)
//双检查锁(但由于内存读写reorder不安全,更具体需要进一步说)
Singleton* Singleton::getInstance() {
if(m_instance==nullptr){
Lock lock;
// 为了提高读性能
if (m_instance == nullptr) {
m_instance = new Singleton();
}
}
return m_instance;
}
C++11 可以采用final实现 (阻止它的派生类重写当前虚函数)
Singleton的懒汉模式与饿汉模式
懒汉模式
第一次初始化的时候才会初始化自己,代码同上。因为每次得要询问if和用到锁,所以如果遇到处理大量数据时,锁会成为整个性能的瓶颈。饿汉模式
Singleton在程序一开始就将自己实例化,之后的GetInstance方法仅返回实例的指针即可,这样就解决了上述提到的if语句影响效率的问题。饿汉模式适用于Singleton在程序运行过程中一直被频繁调用,这样由于预先加载了实例,访问实例时没有if语句,效率更高。
// - 饿汉模式
class Singleton{
private:
Singleton();
Singleton(const Singleton& other);
public:
static Singleton* getInstance(){
return m_instance;
};
static Singleton* m_instance;
};
Singleton* Singleton::m_instance= new Singleton(); //在此直接实例化
另外,对于更加详细的可以查看这篇博客[岳阳-C++单例模式 Singleton的实现]https://www.tianmaying.com/tutorial/singleton