C++中的單例模式


轉自:http://blog.csdn.net/hackbuteer1/article/details/7460019

單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例類的特殊類。通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。顯然單例模式的要點有三個:一是某個類只能有一個實例;二是它必須自行創建這個實例;三是它必須自行向整個系統提供這個實例;

 單例模式其意圖是保證一個類僅有一個實例,並提供一個訪問它的全局訪問點,該實例被所有程序模塊共享。

《設計模式》一書中給出了一種很不錯的實現,定義一個單例類,使用類的私有靜態指針變量指向類的唯一實例,並用一個公有的靜態方法獲取該實例。


class CSingleton
{private:
   CSingleton()   //構造函數是私有的  
     {
   }  
    static CSingleton *m_pInstance;
    public:    
    static CSingleton * GetInstance()
   {      
     if(m_pInstance == NULL)  //判斷是否第一次調用
           
           m_pInstance = new CSingleton();    
               return m_pInstance;
   }
};

GetInstance()使用懶惰初始化,也就是說它的返回值是當這個函數首次被訪問時被創建的。

 上述代碼可能存在的問題:

m_pInstance指向的空間什麼時候釋放呢?更嚴重的問題是,該實例的析構函數什麼時候執行?

一個妥善的方法是讓這個類自己知道在合適的時候把自己刪除,或者說把刪除自己的操作掛在操作系統中的某個合適的點上,使其在恰當的時候被自動執行。
我們知道,程序在結束的時候,系統會自動析構所有的全局變量。事實上,系統也會析構所有的類的靜態成員變量,就像這些靜態成員也是全局變量一樣。利用這個特徵,我們可以在單例類中定義一個靜態成員變量,而它的唯一工作就是在析構函數中刪除單例類的實例

class CSingleton
{private:
   CSingleton()
   {
   }    
   static CSingleton *m_pInstance;  
    class CGarbo   //它的唯一工作就是在析構函數中刪除CSingleton的實例  
      {    
      public:      
       ~CGarbo()
       {        
          if(CSingleton::m_pInstance)
               delete CSingleton::m_pInstance;
       }
   };    
   static CGarbo Garbo;  //定義一個靜態成員變量,程序結束時,系統會自動調用它的析構函數public:    static CSingleton * GetInstance()
   {        if(m_pInstance == NULL)  //判斷是否第一次調用
           m_pInstance = new CSingleton();        return m_pInstance;
   }
};

類CGarbo被定義爲CSingleton的私有內嵌類,以防該類被在其他地方濫用。
程序運行結束時,系統會調用CSingleton的靜態成員Garbo的析構函數,該析構函數會刪除單例的唯一實例

添加一個類的靜態對象,總是讓人不太滿意,所以有人用如下方法來重新實現單例和解決它相應的問題,代碼如下:

class CSingleton
{private:
   CSingleton()   //構造函數是私有的    {
   }
   public:
      static CSingleton & GetInstance()
   {        static CSingleton instance;   //局部靜態變量
       return instance;
   }
};

使用局部靜態變量,非常強大的方法,完全實現了單例的特性,而且代碼量更少,也不用擔心單例銷燬的問題。 但使用此種方法也會出現問題,當如下方法使用單例時問題來了, Singleton singleton = Singleton :: GetInstance(); 這麼做就出現了一個類拷貝的問題,這就違背了單例的特性。產生這個問題原因在於:編譯器會爲類生成一個默認的構造函數,來支持類的拷貝。

最後沒有辦法,我們要禁止類拷貝和類賦值,禁止程序員用這種方式來使用單例,函數的代碼改爲如下:

class CSingleton
{private:
   CSingleton()   //構造函數是私有的    {
   }
   public:  
    static CSingleton * GetInstance()
   {        static CSingleton instance;   //局部靜態變量
       return &instance;
   }
};

可以顯示的聲明類拷貝的構造函數,和重載 = 操作符,新的單例類如下:(我的理解:不將instance設爲private static成員變量,是因爲不清楚它什麼時候被初始化 )

class CSingleton

{private:
   CSingleton()   //構造函數是私有的  
     {
   }
   CSingleton(const CSingleton &);
   CSingleton & operator = (const CSingleton &);
   public:    
   static CSingleton & GetInstance()
   {    
      static CSingleton instance;   //局部靜態變量,相比較指針指向的堆上對象,不用擔心銷燬問題
       return instance;
   }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章