1. 程式人生 > >c++ 單例模式

c++ 單例模式

1.懶漢模式

在第一次用到類例項的時候才會去例項化

  • 方法1:加鎖的經典懶漢實現

class singleton
{
protected:
    singleton()
    {
        pthread_mutex_init(&mutex);
    }
private:
    static singleton* p;
public:
    static pthread_mutex_t mutex;
    static singleton* initance();
};

pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;
singleton* singleton::initance()
{
    if (p == NULL)
    {
        pthread_mutex_lock(&mutex);
        if (p == NULL)
            p = new singleton();
        pthread_mutex_unlock(&mutex);
    }
    return p;
}
  • 方法2:內部靜態變數的懶漢實現

在instance函式裡定義一個區域性的靜態例項,只在第一次執行時建立,所以也可以保證擁有唯一例項。

這裡最好加上鎖,如不加,可能造成執行緒不安全(depends on implementation: e.g. g++ will insert locks, but MSVC will not)。

class singleton
{
protected:
    singleton()
    {
        pthread_mutex_init(&mutex);
    }
public:
    static pthread_mutex_t mutex;
    static singleton* initance();
    int a;
};

pthread_mutex_t singleton::mutex;
singleton* singleton::initance()
{
    pthread_mutex_lock(&mutex);
    static singleton obj;
    pthread_mutex_unlock(&mutex);
    return &obj;
}

2.餓漢模式

在進入main函式前就已經完成物件的定義和初始化,執行緒安全。

但是有隱患,因為c++中對全域性物件的構造順序並沒有明確的規定。假如有一個全域性物件A,其建構函式裡引用如下程式碼餓漢形式的指標,若在A建構函式構造之前以上單例並未構造出來,那就會有問題。

同時要注意,在建構函式裡使用其它類的成員變數,是危險行為。

class singleton
{
protected:
    singleton()
    {}
private:
    static singleton* p;
public:
    static singleton* initance();
};
singleton* singleton::p = new singleton;
singleton* singleton::initance()
{
    return p;
}

3.單例模式的資源釋放

很多情況下資源的釋放是有必要的,如關閉佔用的檔案、斷開與伺服器的連線等等。

沒有使用new時,只需要在解構函式中釋放相關資源即可;

使用了new時,不能在解構函式中delete單例,這樣會造成delete和解構函式的迴圈呼叫,可以使用以下方法:

  • 法1:寫一個函式,主動delete,缺點是容易忘記呼叫該函式。
  • 法2:利用C++ Rall機制(resource acquisition is initialization,資源獲取即初始化),沒有深究到底是啥,大概就是程式在結束的時候,系統會自動析構所有的全域性變數,以及所有類的靜態成員變數。
class CSingleton:
{
public:
    static CSingleton * GetInstance();

protected:
    CSingleton();

private:
    static CSingleton * m_pInstance;
 
    class CGarbo // 它的唯一工作就是在解構函式中刪除CSingleton的例項
    {
    public:
        ~CGarbo()
        {
            if (CSingleton::m_pInstance)
                delete CSingleton::m_pInstance;
        }
    }; 
    static CGarbo Garbo; // 定義一個靜態成員,在程式結束時,系統會呼叫它的解構函式
}

參考: