单例模式是众多设计模式中较为常见的一种。定义单例模式一般满足以下两个定义:
- 1.保证一个类只创建一个实例。
- 2.提供对该实例的全局访问点。
GoF《设计模式》实现单例设计模式的代码:Lazy Singleton
class Singleton
{
public:
static Singleton& Instance()
{
if (instance_ == NULL)
{
instance_ = new Singleton;
}
return *instance_;
}
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton* instance_;
};
- 上述实现中把构造函数声明为私有方法,根本上杜绝外部使用构造函数生成新的类实例。
- 同时禁用拷贝函数与赋值操作符(声明为私有但是不提供实现)避免通过拷贝函数或赋值操作生成新实例。
- 提供静态方法Instance()作为全局访问点,先判断有无现成实例,有直接返回,无就新建一个实例并把实例的指针存储在私有的静态属性instance_中。
- Instance()的返回值类型是引用而不是指针,因为指针可能会被外部调用delete掉。
但上述实现有一个问题,就是如果现在有两个线程A和B,同时通过instance_ == NULL的判断,那么A和B都会创建新实例。所以单例设计模式保证生成唯一实例的规则被打破了。
- 所以上述实现只适用于单线程环境!
下面来看另一种实现: Eager Singleton
{
public:
static Singleton& Instance()
{
return instance;
}
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton instance; //
};
- 上述实现中程序开始时(静态属性instance初始化)的时候就已经创建了实例。
- 在main函数之前初始化,没有线程安全的问题。但潜在问题如果函数外的static对象(nolocal static)在不同编译单元(就是cpp文件和其包含的头文件)中的初始化顺序是为定义的。如果在初始化完成之前就调用Instance()方法则会返回一个未定义的实例。
注:全局静态变量同一个文件中先定义先初始化,不同的文件中不确定,也就是不同cpp文件里的全局static变量初始化顺序是不可控的。
所以上述实现还是有弊端!
再来看一种更优雅的单例模式实现:Meyers Singleton
class Singleton
{
public:
static Singleton& Instance()
{
static Singleton instance;
return instance;
}
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
};
- 上述实现使用local static 局部静态变量,当第一次访问Instance()方法时才创建实例。完美的解决了Eager Singleton中的问题!
网友评论