設計模式——單例模式(C++實現)
一、單例模式定義:
保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點,該例項被所有程式模組共享。
二、應用場景:
比如在某個伺服器程式中,該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例物件統一讀取,然後服務程序中的其他物件再通過這個單例物件獲取這些配置資訊。這種方式簡化了在複雜環境下的配置管理。其他還有如系統的日誌輸出、MODEM的聯接需要一條且只需要一條電話線,作業系統只能有一個視窗管理器,一臺PC連一個鍵盤等等。
三、方式:
根據單例物件建立時間,可分為兩種模式:餓漢模式 + 懶漢模式。
-
懶漢模式:指全域性的單例例項在第一次被使用時構建。
-
餓漢模式:指全域性的單例例項在類裝載時構建。
四、程式碼實現
1.懶漢模式
class Singleton {
private:
Singleton() {} //建構函式是私有的
static Singleton *instance;
public:
static Singleton * GetInstance() {
if(instance == nullptr) //判斷是否第一次呼叫
instance = new Singleton();
return instance;
}
};
Singleton * Singleton::instance = nullptr;
單例類Singleton有以下特徵:
它有一個指向唯一例項的靜態指標instance,並且是私有的;
它有一個公有的函式,可以獲取這個唯一的例項,並且在需要的時候建立該例項;
它的建構函式是私有的,這樣就不能從別處建立該類的例項。
2.懶漢模式+物件釋放
程式在結束的時候,系統會自動析構所有的全域性變數。事實上,系統也會析構所有的類的靜態成員變數,就像這些靜態成員也是全域性變數一樣。利用這個特徵,我們可以在單例類中定義一個這樣的靜態成員變數,而它的唯一工作就是在解構函式中刪除單例類的例項。如下面的程式碼中的Garbo類(Garbo意為垃圾工人):
class Singleton { private: Singleton() {} static Singleton *m_pInstance; class Garbo { //它的唯一工作就是在解構函式中刪除Singleton的例項 public: ~Garbo() { if(Singleton::m_pInstance) delete Singleton::m_pInstance; } }; static Garbo garbo; //定義一個靜態成員變數,程式結束時,系統會自動呼叫它的解構函式 public: static Singleton * GetInstance() { if(m_pInstance == nullptr) //判斷是否第一次呼叫 m_pInstance = new Singleton(); return m_pInstance; } }; Singleton * Singleton::m_pInstance = nullptr;
類Garbo被定義為Singleton的私有內嵌類,以防該類被在其他地方濫用。
程式執行結束時,系統會呼叫Singleton的靜態成員garbo的解構函式,該解構函式會刪除單例的唯一例項。
使用這種方法釋放單例物件有以下特徵:
在單例類內部定義專有的巢狀類;
在單例類內定義私有的專門用於釋放的靜態成員;
利用程式在結束時析構全域性變數的特性,選擇最終的釋放時機;
使用單例的程式碼不需要任何操作,不必關心物件的釋放。
3.餓漢式
使用區域性靜態變數,非常強大的方法,完全實現了單例的特性,而且程式碼量更少,也不用擔心單例銷燬的問題。
class Singleton {
private:
Singleton() {} //建構函式是私有的
public:
static Singleton & getInstance() {
static Singleton instance = new Singleton(); //區域性靜態變數
return instance;
}
};
但是當以如下方法使用單例時問題來了:
Singleton singleton = Singleton::GetInstance();
這麼做就出現了一個類拷貝的問題,這就違背了單例的特性。產生這個問題原因在於:編譯器會為類生成一個預設的建構函式,來支援類的拷貝。
我們要禁止類拷貝和類賦值,禁止程式設計師用這種方式來使用單例:
class Singleton {
private:
Singleton() {} //建構函式是私有的
Singleton(const Singleton &);
Singleton & operator = (const Singleton &);
public:
static Singleton & GetInstance() {
static Singleton instance = new Singleton(); //區域性靜態變數
return instance;
}
};
4.執行緒安全——雙重檢測鎖定(Double Checked Locking)
class Singleton {
private:
Singleton() {} //建構函式是私有的
static Singleton *instance;
public:
static Singleton * GetInstance() {
if(instance == nullptr) { //判斷是否第一次呼叫
lock();
if(instance == nullptr)
instance = new Singleton();
unlock();
}
return instance;
}
};
Singleton * Singleton::instance = nullptr;
DCL用於在多執行緒環境下保證單一建立Singleton物件。第一次check不用加鎖,但是第二次check和建立物件必須加鎖。由於編譯器可能會優化程式碼,亂序執行,可能導致DCL失效。例如:
m_Instance = new Singleton(); 這個語句會分成三步完成:
(1)分配記憶體,
(2)在已經分配的記憶體上呼叫建構函式建立物件,
(3)將物件賦值給指標m_Instance .
但是這個順序很可能會被改變為1,3,2。如果A執行緒在1,3執行完後,B執行緒執行第一個條件判斷if(m_Instance ==0),此時鎖不能起到保護作用。B執行緒會認為m_Instance 已經指向有效物件,可以去使用了。嘿嘿,災難發生。
volatile對於執行順序也沒有幫助,解決不了DCL的問題。
5.執行緒安全——pthread_once
template<typename T>
class Singleton : boost::noncopyable {
public:
static T& getInstance() {
pthread_once(&ponce_, &Singleton::init);
return *value_;
}
private:
Singleton();
~Singleton();
static void init() {
value_ = new T();
}
private:
static pthread_once_t ponce_;
static T* value_;
};
template<typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;
template<typename T>
T * Singleton<T>::value_ = nullptr;
參考《Linux多執行緒服務端程式設計》陳碩 2.5節。
使用pthread_once_t來保證執行緒安全。執行緒安全性由Pthreads庫保證。
沒有考慮物件的銷燬,在長時間執行的伺服器程式裡,這不是一個問題,反正程序也不打算正常退出。在短期執行的程式中,程式退出時自然就釋放所有資源了。
相關推薦
設計模式——單例模式(C++實現)
一、單例模式定義: 保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點,該例項被所有程式模組共享。 二、應用場景: 比如在某個伺服器程式中,該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例物件統一讀取,然後服務程序中的其他物件再通過這個單例物件獲取這些配置
Head First 設計模式(C++實現):單例模式:Singleton
單例模式:確保一個類只有一個例項,並提供一個全域性訪問點 1 .經典單例模式實現 我們都很清楚一個簡單的單例模式該怎樣去實現:建構函式宣告為private或protect防止被外部函式例項化,內部儲存一個private static的類指標儲存唯一的例項,例項的動
設計模式-單例模式-C++實現
單例模式:保證一個類提供且僅提供一例項,並提供一個訪問它的全域性訪問點。 場景: 1.當類只能有一個例項並且客戶可以從一個公共的介面訪問到例項; 2.當這個唯一的例項應該是通過子類化可擴充套件的,並且客戶應該無需更改程式碼就能使用一個擴充套件的例項。 #include <s
設計模式-單例模式(餓漢式及懶漢式的Java實現)
單例模式 單例模式在程式設計中使用的頻率非常之高,其設計的目的是為了在程式中提供唯一一個物件(保證只被構造一次),例如寫入日誌的log物件,windows的工作管理員實現(只能開啟一個)。這裡主要介紹單例模式使用Java的實現(包括餓漢式及懶漢式)。 實現
設計模式——單例模式C++實現
引出問題: 設計一個類,我們只能生成該類的一個物件例項。 不好的解法:只適用於單執行緒環境 因為該類只能生成一個物件例項,那麼該類的建構函式必須是私有的,從而避免他人建立例項。在需要的時候建立該類的一個物件。 下面是程式實現: /****************
設計模式——抽象工廠模式(C++實現)
concrete out png return style bsp ctp img using 1 #include <iostream> 2 #include <string> 3 4 usin
設計模式——觀察者模式(C++實現)
ace mes des ret rtu cto pattern virt date 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>
[轉]設計模式--單例模式(一)懶漢式和餓漢式
打印 是否 調用構造 餓漢 一段 tools 會有 輸出結果 java 單例模式是設計模式中比較簡單的一種。適合於一個類只有一個實例的情況,比如窗口管理器,打印緩沖池和文件系統, 它們都是原型的例子。典型的情況是,那些對象的類型被遍及一個軟件系統的不同對象訪問,因此需要一個
設計模式——命令模式(C++實現)
clear cto ive pre urn bak std oot style 1 [root@ ~/learn_code/design_pattern/19_order]$ cat order.cpp 2 #include <
設計模式——職責鏈模式(C++實現)
delet hand jin void ng- nbsp request req oot 1 #include <iostream> 2 #include <string> 3 4 using namesp
設計模式——中介者模式/調停者模式(C++實現)
con 分享 else .cn sign name 得到 ted esp 1 #include <iostream> 2 #include <string> 3 4 using namespace std;
設計模式——單例模式(C++)
clu win 安全 iostream public size turn instance stat 一: 餓漢式單例: 靜態區初始化instance,然後通過getInstance返回。這種方式沒有多線程的問題,是一種以空間換時間的方式,不管程序用不用,都會構造唯一的
C#設計模式--單例模式
資源 let readonly eat 私有靜態變量 sta 技術分享 span ret 目的:避免對象的重復創建 單線程具體的實現代碼 /// <summary> /// 私有化構造函數 /// </summary>
C++設計模式-單例模式
con git god www light nullptr return post gpo 版權聲明:若無來源註明,Techie亮博客文章均為原創。 轉載請以鏈接形式標明本文標題和地址: 本文標題:C++設計模式-單例模式 本文地址:http://techieli
C#設計模式——單例模式
code 關閉 object 需要 rm2 學習 single C# oid 一、單例模式定義: 確保一個類只有一個實例,並提供一個訪問它的全局訪問點。 二、背景: 當我們的系統中某個對象只需要一個實例的情況,例如:操作系統中只能有一個任務管理器,操作文件時,同一時間內只允
php實現設計模式————單例模式
php實現設計模式————單例模式 什麼是單例模式 為什麼要使用單例模式 php中有哪些方式實現新建一個物件例項 如何阻止這種例項化實現理想的單例模式 程式碼實現 什麼是單例模式 為什麼要使用單例模式 php中有哪些方式實現新建一個物件例項 1. ne
C#設計模式 —— 單例模式
嗯,這是本人的第一篇隨筆,就從最簡單的單例模式開始,一步一步地記錄自己的成長。 單例模式是最常見的設計模式之一,在專案程式碼中幾乎隨處可見。這個設計模式的目的就是為了保證例項只能存在一個。單例模式往下還能再細分為懶漢模式和餓漢模式。下面逐個來看。 1.餓漢模式 餓漢模式的做法是在類載入的時候
設計模式之單例模式(關鍵詞:設計模式/單例模式/單件模式)
設計模式 單例模式 定義 單例模式:允許一些物件中只存在 1 個例項。 類裝飾器版本 1:使用 1 個全域性字典,儲存所有類的例項。 instances = {} def getInstances(aClass, *args): if aClass not in i
設計模式|單例模式(2) 單例模式下反序列化和反射帶來的安全問題
接上篇 單例模式(1) 序列化破壞單例模式 餓漢式的單例類 public class HungarySingleton { private final static HungarySingleton hungarySingleton = new Hu
Java設計模式-單例模式(二)單例模式類
餓漢式單例類 餓漢式單例類在載入時單例物件已經被建立。程式碼如下: /** * 懶漢式單例 * @Author: Rick * @Date: 2018/10/31 17:44 */ public class EagerSingleton { pr