题目:
设计一个类,我们只能生成该类的一个实例。
解答:
单例模式的类有以下几个特征:
1.构造函数是private。
2.有一个唯一实例的静态指针,且是private。
3.有一个public接口函数,获得该唯一实例的指针。
解法一:
按照上面的特征实现的单例类如下:
class Singleton{
public:
static Singleton* getInstance(); //获得实例
private:
Singleton();
static Singleton* m_pInstance; //static声明
};
Singleton* m_pInstance = NULL; //static定义
Singleton* getInstance()
{
if (m_pInstance == NULL) m_pInstance = new Singleton();
return m_pInstance;
}
但是上述类存在static变量,如果在单线程模式下OK,但是在多线程模式下,就可能产生与初始化有关的“竞速形势”(条款04)。
条款04中提供了一种方法解决“竞速形势”,就是在程序的单线程启动阶段,手动调用所有reference-returning函数。这显然有点麻烦。
以后补充多线程安全的单例模式。
解法二:利用互斥锁
可以用一个互斥锁将该方法锁住,每次只能有一个线程访问该方法,缺点是加锁是耗时操作,效率较低。
class Singleton{
public:
static Singleton* getInstance(); //获得实例
private:
Singleton();
static Singleton* m_pInstance; //static声明
};
Singleton* m_pInstance = NULL; //static定义
Singleton* getInstance()
{
lock(mutex){ //互斥锁
if (m_pInstance == NULL) m_pInstance = new Singleton();
return m_pInstance;
}
}
效率比这个高的是加锁前判断实例是否已经存在。
解法三(强烈推荐):利用静态构造函数(设计模式中的方法)
其实一旦设置好m_pInstance就不需要同步了,因此提前创建实例,而不用延迟实例化的方法。
class Singleton{
private:
Singleton();
static Singleton* m_pInstance = new Singleton(); //static声明
public:
static Singleton* getInstance(){ return m_pInstance; } //获得实例
};
可惜,上面会提示错误:a member with a in-class initializer must be const
改成下面这样可以:
class Singleton{
private:
Singleton();
static const Singleton* m_pInstance ; //static声明
public:
static const Singleton* getInstance(){ return m_pInstance; } //获得实例
};
const Singleton* Singleton::m_pInstance = new Singleton();