单例模式很好理解,就是只允许创建该类的一个实例。
经典版
class Singleton { public: static Singleton& getInstance() { static Singleton instance; return instance; } private: Singleton() {} Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
- 构造函数声明为private,则只有Singleton类的代码才能调用构造函数。
- 利用局部静态变量达到实例只有一个的要求。
- 局部静态变量的另一个优点是lazy initialization,只有在第一次调用getInstance()时才创建该变量。
- getInstance()返回的是对局部静态变量的引用。如果返回的是指针,getInstance()的调用者很可能会误认为他要检查指针的有效性,并负责销毁。
可能有人要说上面的实现不是线程安全的。
的确,在C++11之前不是,但是在C++11中却是线程安全的。
因为新的C++标准规定:当一个线程正在初始化一个变量的时候,其他线程必须得等到该初始化完成以后才能访问它。
if control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
那要是不允许使用C++11呢?那就加锁喽。
static Singleton& getInstance() { lock(); static Singleton instance; unlock(); return instance; }
DCL版(double-checked locking)
class Singleton { private: static Singleton *instance; Singleton() {}; public: static Singleton* getInstance() { if (instance == NULL) { lock(); if (instance == NULL) instance = new Singleton; unlock(); } return instance; } }; Singleton* Singleton::instance = NULL;
第一次check的目的是为了只在实例不存在的情况下才进行加锁操作。
第二次check的目的是为了确认在加锁之后,实例是否存在。如果存在就不需要new了。
关于instance = new Singleton;这句,又涉及到CPU指令重排的问题,什么volatile啊,memory barrier啊,内容太多,记不住了。
eager initialization
class Singleton { private: static Singleton *instance; Singleton() {}; public: static Singleton* getInstance() { return instance; } }; Singleton* Singleton::instance = new Singleton;
reference: