設計模式學習筆記1——單例模式

單例模式(Singleton)

保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

代碼:https://github.com/duyilong/Design-pattern/tree/master/Singleton

  • 保證僅有一個實例:不允許隨意new,將構造函數複製構造函數賦值運算符聲明爲私有private,注意,析構函數也要聲明爲私有。
  • 全局訪問點:靜態的GetInstance方法、靜態的DeleteInstance方法。

根據instance創建的時間分爲餓漢式和懶漢式兩種實現方式。

餓漢式:the Singleton instance is EARLY createed at compile time。

懶漢式:the Singleton instance is LAZILY created at runtime。

先看代碼,

1. 線程安全單例類的懶漢式實現

#include <mutex> //std::mutex

class Singleton_lazy
{
public:
    static Singleton_lazy *&GetInstance() ; //注意返回值類型,對一個指針變量的引用
    static void DeleteInstance();

private:
    Singleton_lazy() {}
    ~Singleton_lazy() {}
    Singleton_lazy(const Singleton_lazy &singleton) {}
    const Singleton_lazy operator=(const Singleton_lazy &singleton) {}

private:
    static Singleton_lazy *m_instance;
    static std::mutex m_mutex;
};

// 初始化靜態成員變量
Singleton_lazy *Singleton_lazy::m_instance = NULL;
std::mutex      Singleton_lazy::m_mutex;

// 成員函數實現
Singleton_lazy *&Singleton_lazy::GetInstance()
{
    if (m_instance == NULL) //雙重鎖定,防止每次調用GetInstance都要加鎖,只有發現需要實例化的時候才加鎖
    {
        //如果兩個線程同時通過了第一重的m_instance==NULL判斷,就會有一個先加鎖然後創建出來m_instance。
        //所以還需要第二重判斷m_instance==NULL,防止被實例化出多個對象
        std::unique_lock<std::mutex> lock(m_mutex); //加鎖
        if (m_instance == NULL)                     //
        {
            m_instance = new Singleton_lazy;
        }
    }
    return m_instance;
}

void Singleton_lazy::DeleteInstance()
{
    std::unique_lock<std::mutex> lock(m_mutex);
    if (m_instance)
    {
        delete m_instance;
        m_instance = NULL;
    }
}

注意:

  1. GetInstance方法的返回類型。對一個指針變量的引用,可行;指向引用的指針,不對。
  2. GetInstance方法的雙重鎖定。
  3. 在類的聲明體外對static成員變量進行定義和初始化。(注意:對於一般的類,可以只在類體外對static成員定義,然後在構造函數中初始化。注意區分聲明、定義和初始化的區別。聲明 [聲明語句爲類體內的static std::mutex m_mutex] 不會給變量分配內存空間,定義 [定義語句爲類體外的std::mutex Singleton_lazy::mutex; 對instance變量的定義和初始化在同一個語句中] 纔會給變量分配內存空間。)

2.C++11線程安全單例類的懶漢式實現

class Single
{
public:
    // 獲取單實例對象
    static Single &GetInstance()
    {
        // c++11內部靜態變量具有線程安全性,所以可以利用這個特性很簡單就實現一個線程安全的單例類
        // 局部靜態特性的方式實現單實例
        static Single instance;
        return instance;
    }

private:
    Single();                                      // 禁止外部構造
    ~Single();                                     // 禁止外部析構
    Single(const Single &signal);                  // 禁止外部複製構造
    const Single &operator=(const Single &signal); // 禁止外部賦值操作
};

3.單例類的餓漢式實現(天生線程安全)

餓漢式利用語言運行時庫的“靜態初始化”特性,在單例類的實現代碼一加載到程序中的時候,就在內存中實例化出了一個單例類的實例。

// 單例類餓漢式實現
// 本身具有線程安全性
#include <iostream>
using namespace std;

namespace myspace
{

class singleton_early
{
public:
    static singleton_early *GetInstance()
    {
        return g_psingle;
    }

    static void DeleteInstance()
    {
        if (g_psingle)
        {
            delete g_psingle;
            g_psingle = NULL;
        }
    }

    void test()
    {
        printf("test early singleton\n");
    }

private:
    singleton_early() {}
    ~singleton_early() {}
    singleton_early(const singleton_early &single) {}
    const singleton_early &operator=(const singleton_early &single) {}

private:
    static singleton_early *g_psingle;
};

// 靜態成員變量的初始化
singleton_early *singleton_early::g_psingle = new singleton_early;
} // namespace myspace

 

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