單例模式

單例模式

  1. 單例類保證全局只有一個唯一實例對象。
  2. 單例類提供獲取這個唯一實例的接口。

(1).餓漢模式

#include<iostream>
#include <mutex>
using namespace std;

template <class T>
class EagerSingleton
{
public :
                 static T * GetInstance()
                {
                                assert(_instance);
                                 return _instance;
                }
                 //實例銷燬(1)一般情況下,不必在乎,因爲全局就這一個變量,全局都要用,
                 //不知道什麼時候銷燬比較合適,一般他的生命週期就是軟件的生命週期,
                 //軟件結束,他就結束了(程序結束時會自動釋放它佔用的內存資源)
                 //(2)當在類中打開了文件句柄,數據庫連接等,需要手動釋放時,就得顯示銷燬這個實例
                 static void DelInstance()
                {
                                 if (_instance)
                                {
                                                 delete _instance;
                                                _instance = NULL ;
                                }
                }

                 //RAII  自動回收實例對象
                 class GC
                {
                 public :
                                ~GC()
                                {
                                                DelInstance();
                                }
                };
protected :
                EagerSingleton();
                EagerSingleton( const EagerSingleton & s);
                 EagerSingleton & operator = (const EagerSingleton& s);
protected :
                 static T * _instance;
};

template <class T>
T * EagerSingleton <T>::_instance = new T ;

(2).懶漢模式

template <class T>
class LazySingleton
{
public :
                 T * GetInstance()
                {
                                 // 使用雙重檢查,提高效率,避免高併發場景下每次獲取實例對象都進行加鎖
                                 if (_instance == NULL )
                                {
                                                mtx.lock();
                                                 if (_instance == NULL )
                                                {
                                                                 //下面的tmp = new LazyEagerSingleton();編譯器可能會進行優化
                                                                 //上面的代碼分爲三個部分:1.分配空間 2.調用構造函數 3. 賦值
                                                                 //編譯器優化可能導致2,3重排。這樣可能導致高併發場景下,
                                                                 //其他線程獲取到未調用構造函數初始化的對象。解決:加入內存柵欄

                                                                 //就相當於,當程序中已存在一個未調用構造函數初始化的對象,時間片到了,
                                                                 //其他線程以爲對象已創建好就直接用了,對吧
                                                                 T * tmp = new T;
                                                                MemoryBarrier();
                                                                _instance = tmp;
                                                }
                                                mtx.unlock();
                                }
                                 return _instance;
                }
protected :
                //構造函數定義爲私有,限制只能在類內創建對象
                LazySingleton();
                LazySingleton( const LazySingleton & s);
                 LazySingleton & operator=(const LazySingleton& s);

protected :
                 //1.靜態成員無須創建任何對象實例就可以訪問。
                 //2.靜態對象在main函數之前初始化,這時只有主線程運行,所以是線程安全的。
                 static T * _instance;
                 static mutex mtx;
};
template <class T>
T * LazySingleton <T>::_instance = NULL ;

參考文件:http://blog.csdn.net/lovelion/article/details/8229621

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章