【引言】
单件模式的应用场景大家都不陌生,目的也很明确,就是一个类保证只有一个实际,比如项目中的资源管理器,或打log的类,都比较适合单件模式,话不多说,先贴一段代码吧。
class Singleton
{
public:
static Singleton* Instance();
static void Destroy();
virtual void Print();
protected:
Singleton();
private:
static Singleton* _instance;
};
Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance()
{
if (_instance == 0) //线程不安全
{
_instance = new Singleton;
}
return _instance;
}
void Singleton::Destroy()
{
if (_instance != 0)
{
delete _instance;
_instance = 0;
}
}
Singleton::Singleton()
{
printf("Create Singleton/n");
}
void Singleton::Print()
{
printf("Singleton Print/n");
}
int main(void)
{
Singleton::Instance()->Print();
return 0;
}
上面的实现是GOF中的标准实现,但是这种方案有些问题,如下所示:
1. 不是线程安全的,如果两个线程A、B,A先调用if(_instance==0),这里判断结果是单件未实例化,这时cpu被B抢占,B也执行到同一行,判断结果也是未实例化,那么继续执行,_instance就会被实例化两次。
2. 在全局变量或静态变量中调用单件模式的接口,比如上面的单件有个接口是int GetId(); 那可以定义一个全局的ID,如下所示: int g_Id = Singleton::Instance()->GetId(); 这时全量变量g_Id和静态变量_instance之间就存在一个初始化先后的问题,而C++并未对这类非局部静态变量初始化顺序做说明。
针对上面的问题,给出一种改进的实现。
【改进方案】
下面的实现是采用静态局部变量的方案,保证在进程的生命周期中只实例化一次,如下所示:
class Singleton
{
public:
static Singleton* Instance();
virtual void Print();
protected:
Singleton();
};
Singleton* Singleton::Instance()
{
statice Singleton _instance;
return &_instance;
}
Singleton::Singleton()
{
printf("Create Singleton/n");
}
void Singleton::Print()
{
printf("Singleton Print/n");
}
int main(void)
{
Singleton::Instance()->Print();
return 0;
}