C++设计模式

单例模式

懒汉版(Lazy Singleton):单例实例在第一次被使用时才进行初始化,这叫做延迟初始化。

C++11规定了local static在多线程条件下的初始化行为,要求编译器保证了内部静态变量的线程安全性。这样,只有当第一次访问getInstance()方法时才创建实例。这种方法也被称为Meyers’ Singleton。C++0x之后该实现是线程安全的,C++0x之前仍需加锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Singleton
{
private:
Singleton() { };
~Singleton() { };
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
};

饿汉版(Eager Singleton):指单例实例在程序运行时被立即执行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// version 1.3
class Singleton
{
private:
static Singleton instance;
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance() {
return instance;
}
}

// initialize defaultly
Singleton Singleton::instance;

由于在main函数之前初始化,所以没有线程安全的问题。但是潜在问题在于no-local static对象(函数外的static对象)在不同编译单元中的初始化顺序是未定义的。也即,static Singleton instance;和static Singleton& getInstance()二者的初始化顺序不确定,如果在初始化完成之前调用 getInstance() 方法会返回一个未定义的实例。

总结:

  • Eager Singleton虽然是线程安全的,但存在潜在问题;
  • Lazy Singleton通常需要加锁来保证线程安全,但局部静态变量版本在C++11后是线程安全的;
  • 局部静态变量版本(Meyers Singleton)最优雅。