天天看點

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;
    }
};      
{private:
    CSingleton()   //構造函數是私有的  
      {
    }
    CSingleton(const CSingleton &);
    CSingleton & operator = (const CSingleton &);
    public:    
    static CSingleton & GetInstance()
    {     
       static CSingleton instance;   //局部靜态變量,相比較指針指向的堆上對象,不用擔心銷毀問題
        return instance;
    }
};      

繼續閱讀