单例模式(singleton pattern)

单例模式很好理解,就是只允许创建该类的一个实例。

经典版

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:

C++ 线程安全的单例模式

面试中的Singleton

C++中多线程与Singleton的那些事儿

单例模式(Singleton)及其C++实现

posted @ 2015-08-25 22:09  Sawyer Ford  阅读(209)  评论(0编辑  收藏  举报