1. 程式人生 > >C++單例設計模式

C++單例設計模式

一.單例模式含義
通過單例模式,可以保證系統中一個類只有一個例項,而且該例項易於外界訪問,從而方便對例項個數的控制,並節約系統資源。

二.採用單例模式的動機和原因
對於系統中的某個類來說,只有一個例項很重要。
例如:一個系統中有多個列印任務,但是隻能有一個正在工作的任務。
一個系統只能有一個視窗管理器或檔案系統。
一個系統只能有一個計時工具或ID(序號)生成器。
如果不使用機制對視窗物件進行唯一化,將彈出多個視窗,如果這些視窗顯示的內容完全一致,則是重複物件,浪費記憶體資源;如果這些視窗顯示的內容不一致,則意味著在某一瞬間系統有多個狀態,與實際不符,也會給使用者帶來誤解,不知道哪一個才是真實的狀態。因此有時確保系統中某個物件的唯一性即一個類只能有一個例項非常重要。

如何保證一個類只有一個例項並且這個例項易於被訪問呢?定義一個全域性變數可以確保物件隨時都可以被訪問,但不能防止我們例項化多個物件。一個更好的解決辦法是讓類自身負責儲存它的唯一例項。這個類可以保證沒有其他例項被建立,並且它可以提供一個訪問該例項的方法。這就是單例模式的模式動機。

【單例模式優缺點】
【優點】
一、例項控制
單例模式會阻止其他物件例項化其自己的單例物件的副本,從而確保所有物件都訪問唯一例項。
二、靈活性
因為類控制了例項化過程,所以類可以靈活更改例項化過程。
【缺點】
一、開銷
雖然數量很少,但如果每次物件請求引用時都要檢查是否存在類的例項,將仍然需要一些開銷。可以通過使用靜態初始化解決此問題。
二、可能的開發混淆
使用單例物件(尤其在類庫中定義的物件)時,開發人員必須記住自己不能使用new關鍵字例項化物件。因為可能無法訪問庫原始碼,因此應用程式開發人員可能會意外發現自己無法直接例項化此類。
三、物件生存期
不能解決刪除單個物件的問題。在提供記憶體管理的語言中(例如基於.NET Framework的語言),只有單例類能夠導致例項被取消分配,因為它包含對該例項的私有引用。在某些語言中(如 C++),其他類可以刪除物件例項,但這樣會導致單例類中出現懸浮引用

**單例模式的簡單理解
1 單例模式 只允許建立一個物件,因此節省記憶體,加快物件訪問速度,因此物件需要被公用的場合適合使用,如多個模組使用同一個資料來源連線物件等等
2 單例的缺點 就是不適用於變化的物件,如果同一型別的物件總是要在不同的用例場景發生變化,單例就會引起資料的錯誤,不能儲存彼此的狀態。
用單例模式,就是在適用其優點的狀態下使用**

三.教科書裡面的單例模式
我們都很清楚一個簡單的單例模式該怎樣去實現:建構函式宣告為private或protect防止被外部函式例項化,內部儲存一個private static的類指標儲存唯一的例項,例項的動作由一個public的類方法代勞,該方法也返回單例類唯一的例項。

class singleton
{
protected:
 singleton(){}
privete:
 static singleton *p; //宣告一個靜態例項,a.宣告為靜態的好處,只有通過靜態成員函式訪問
 //靜態成員變數,然後在類外,之間可以通過類名訪問成員函式,而不需要通過物件。
public:
 static singleton *insance(); 
}

singleton* singleton::p=NULL;
singleton* singleton::insance(){
 if(p==NULL)
  p=new singleton;
 return p;
}

這是一個很棒的實現,簡單易懂。但這是一個完美的實現嗎?不!該方法是執行緒不安全的,考慮兩個執行緒同時首次呼叫instance方法且同時檢測到p是NULL值,則兩個執行緒會同時構造一個例項給p,這是嚴重的錯誤!同時,這也不是單例的唯一實現!

四.懶漢與餓漢
單例大約有兩種實現方法:懶漢與餓漢。
懶漢:故名思意,不到萬不得已,就不會去例項化類,也就是說在第一次用到類例項的時候才會去例項化,所以上邊的經典方法被歸為懶漢實現;
餓漢:餓了肯定要飢不擇食。所以在單例類定義的時候就進行例項化。

特點與選擇:
a.由於要進行執行緒同步,所以在訪問量比較大,或者可能訪問的執行緒比較多時,採用餓漢實現,可以實現更好的效能。這是以空間換時間。

b.在訪問量較小時,採用懶漢實現。這是以時間換空間。

五,執行緒安全的懶漢實現
方法1:加鎖的經典懶漢實現: