1. 程式人生 > >單例模式-解構函式的深入理解

單例模式-解構函式的深入理解

singleton單例模式 單件模式      保證一個類中僅有一個例項,並且提供一個訪問他的全域性訪問點
a. 懶漢式:使用的時候才建立,多執行緒訪問的時候執行緒不安全(雙檢鎖)
b. 餓漢式:類檔案載入的時候已經建立好了物件,如果物件一直沒有使用,則類物件浪費空間

#注意
    1. 建構函式私有化, 
    2. 私有的靜態類指標指向類的例項(類外宣告)
    3. 共有的靜態方法去獲取一個訪問例項的訪問點
   
4. 解構函式需要定義一個巢狀類的解構函式去釋放單例
   5. 絕對不要在單例的解構函式中釋放單例(coredump)!!!!!!!!! 詳情看下面有問題的單例程式碼

#include <iostream>
using namespace std;

class A
{
    private:
        static A *m_p;

    public:
        static A *getSingleTon()
        {
            if(NULL == m_p)
            {
                m_p = new A();

            }

            return m_p;

        }


/*        ~A()
        {
            if(NULL != m_p)
            {
                cout << "xxx" << endl;

                delete m_p; // 遞迴呼叫析構
                m_p = NULL;

                cout << "yyy" << endl; // 永遠也不會執行

            }

        }
*/
};

A* A::m_p = NULL;


int main()
{
    A *p = A::getSingleTon();
    delete p;

    return 0;

}

所以 單例解構函式:定義一個靜態的巢狀類物件的解構函式去析構單例物件 ,簡單思想看如下程式碼:
#include<iostream>
using namespace std;

//巢狀類去析構單例類物件
class A
{
    public:
    ~A()
    {
        cout << "deconstructor A" << endl;
    }
    class B
    {
        public:
        ~B()      //巢狀類成員的解構函式去析構單例函式的物件
        {
            cout << "呼叫巢狀 deconstructor B" << endl; 
        }
    };

    private:
    static  B b;
    static int a;
};
int  A::a = 10;
A::B A::b;        //巢狀靜態類成語,必須類外宣告

int main()
{
    return 0;
}

需要清楚一下幾點:   1、單例中的 new 的物件需要delete釋放。   2、delete釋放物件的時候才會呼叫物件的解構函式。   3、如果在解構函式裡呼叫delete,那麼程式結束時,根本進不去解構函式,怎麼會delete。   4、如果程式結束能自動析構,那麼就會造成一個析構的循壞,所以new對應於delete。 ///////////////////////////////////////////////////////////////////////////////////////////////// A.懶漢式單例模式
//懶漢式 (建立的時候採取new例項)以時間換取空間,執行緒不安全
class singleton_L
{
    public:
        static singleton_L* getinstance()
        {
            if(instance == NULL)
            {
                instance = new singleton_L();
            }
            return instance;
        }
        
        //實際上在解構函式中析構物件是一種錯誤的做法,會呼叫,切是一個死遞迴,正確做法是建立一個巢狀的析構類
        /*~singleton_L()
        {
            if(instance != NULL)
            {
                delete instance;
                instance = NULL;
            }
        
            cout << "~singleton_L()" << endl;
        }*/
    private:
        class Garbo //設定為私有防止外界訪問
        {
            public:
                ~Garbo()//實際去析構new的單例物件
                {
                    if(singleton_L::instance != NULL)
                    {
                        cout << "delete singleton" << endl;
                        delete singleton_L::instance;
                        singleton_L::instance = NULL;
                    }
                }
        };
    
    private:
        singleton_L(){}
        static singleton_L*  instance;  //單例唯一實力
        static Garbo garbo;             //靜態私有的巢狀類物件,防止被外界訪問
};

singleton_L*       singleton_L::instance = NULL;
singleton_L::Garbo singleton_L::garbo;  //靜態類物件類外聲
B懶漢式 ,執行緒安全方法
//懶漢式 執行緒安全式(雙檢鎖)
/*
  所謂雙重檢查加鎖機制,指的是:並不是每次進入getInstance方法都需要同步,而是先不
同步,進入方法過後,先檢查例項是否存在,如果不存在才進入下面的同步塊,這是第一重
檢查。進入同步塊過後,再次檢查例項是否存在,如果不存在,就在同步的情況下建立一個
例項,這是第二重檢查。這樣一來,就只需要同步一次了,從而減少了多次在同步情況下進
行判斷所浪費的時間。
*/
class singleton_L_Lock
{
    public:
        static singleton_L_Lock* getinstance()
        {
            if(instance == NULL)
            {
                pthread_mutex_lock(&mutex);  //加鎖
                if(instance == NULL)
                    instance = new singleton_L_Lock();
                pthread_mutex_unlock(&mutex);
            }
            return instance;
        }

    private:
        class GGGarbo
        {
            public:
                ~GGGarbo()
                {
                    if(singleton_L_Lock::instance != NULL)
                    {
                        delete singleton_L_Lock::instance;
                        singleton_L_Lock::instance = NULL;
                    }
                }
        };
    public:
        static pthread_mutex_t mutex;
    private:
        singleton_L_Lock()
        {
            pthread_mutex_init(&mutex, NULL);
        }
    private:
        static singleton_L_Lock*  instance;
        static GGGarbo gggarbo;
};

singleton_L_Lock* singleton_L_Lock::instance = NULL;
pthread_mutex_t   singleton_L_Lock::mutex;  
singleton_L_Lock::GGGarbo singleton_L_Lock::gggarbo;
c.餓漢式  ,不牽扯執行緒安不安全,以空間換時間
//餓漢式(在定義例項的時候就去new物件)以空間換時間
class singleton_E
{
    public:
        static singleton_E* getinstance()
        {
            return instance;
        }

       // ~singleton_E(){}
        class GGarbo
        {
            public:
                ~GGarbo()
                {
                    if(singleton_E::instance != NULL)
                    {
                        cout << "delete singleton_E" << endl;
                        delete singleton_E::instance;
                        singleton_E::instance = NULL;
                    }
                }
        };
    private:
        singleton_E(){}
        static singleton_E* instance;
        static GGarbo ggarbo;
};

singleton_E*        singleton_E::instance = new singleton_E();
singleton_E::GGarbo singleton_E::ggarbo;
以上就是我對單例模式的一些理解心得,如有不對的地方多多指教,哈哈哈。