C 中的單例模式介紹

2022-10-04 05:24:07 字數 4178 閱讀 4199

有很多地方需要這樣的功能模組,如系統的日誌輸出,gui應用必須是單滑鼠,modem的聯接需要一條且只需要一條**線,作業系統只能有乙個視窗管理器,一台pc連乙個鍵盤。

單例模式有許多種實現方法,在c++中,甚至可以直接用乙個全域性變數做到這一點,但這樣的**顯的很不優雅。 使用全域性物件能夠保證方便地訪問例項,但是不能保證只宣告乙個物件——也就是說除了乙個全域性例項外,仍然能建立相同類的本地例項。

《設計模式》一書中給出了一種很不錯的實現,定義乙個單例類,使用類的私有靜態指標變數指向類的唯一例項,並用乙個公有的靜態方法獲取該例項。

單例模式通過類本身來管理其唯一例項,這種特性提供了解決問題的方法。唯一的例項是類的乙個普通物件,但設計這個類時,讓它只能建立乙個例項並提供對此例項的全域性訪問。唯一例項類singleton在靜態成員函式中隱藏建立例項的操作。習慣上把這個成員函式叫做instance(),它的返回值是唯一例項的指標。

定義如下:

複製** **如下:

class csingleton

private:

csingleton(){};

static csingleton * m_pinstance;

};使用者訪問唯一例項的方法只有getinstance()成員函式。如果不通過這個函式,任何建立例項的嘗試都將失敗,因為類的建構函式是私有的。getinstance()使用懶惰初始化,也就是說它的返回值是當這個函式首次被訪問時被建立的。這是一種防彈設計——所有getinstance()之後的呼叫都返回相同例項的指標:

csingleton* p1 = csingleton :: getinstance();

csingleton* p2 = p1->getinstance();

csingleton & ref = * csingleton :: getinstance();

對getinstance稍加修改,這個設計模板便可以適用於可變多例項情況,如乙個類允許最多五個例項。

單例類csingleton有以下特徵:

它有乙個指向唯一例項的靜態指標m_pinstance,並且是私有的;

它有乙個公有的函式,可以獲取這個唯一的例項,並且在需要的時候建立該例項;

它的建構函式是私有的,這樣就不能從別處建立該類的例項。

大多數時候,這樣的實現都不會出現問題。有經驗的讀者可能會問,m_pinstance指向的空間什麼時候釋放呢?更嚴重的問題是,該例項的析構函式什麼時候執行?

如果在類的析構行為中有必須的操作,比如關閉檔案,釋放外部資源,那麼上面的**無法實現這個要求。我們需要一種方法,正常的刪除該例項。

可以在程式結束時呼叫getinstance(),並對返回的指標掉用delete操作。這樣做可以實現功能,但不僅很醜陋,而且容易出錯。因為這樣的附加**很容易被忘記,而且也很難保證在delete之後,沒有**再呼叫getinstance函式。

乙個妥善的方法是讓這個類自己知道在合適的時候把自己刪除,或sbgybuc者說把刪除自己的操作掛在作業系統中的某個合適的點上,使其在恰當的時候被自動執行。

我們知道,程式在結束的時候,系統會自動析構所有的全域性變數。事實上,系統也會析構所有的類的靜態成員變數,就像這些靜態成員也是全域性變數一樣。利用這個特徵,我們可以在單例類中定義乙個這樣的靜態成員變數,而它的唯一工作就是在析構函式中刪除單例類的例項。如下面的**中的cgarbo類(garbo意為垃圾工人):

複製** **如下:

class csingleton

;    static csingleton * m_pinstance;

class cgarbo //它的唯一工作就是在程式設計客棧析構函式中刪除csingleton的例項

}static cgabor garbo; //定義乙個靜態成員,程式結束時,系統會自動呼叫它的析構函式

};類cgarbo被定義為csingleton的私有內嵌類,以防該類被在其他地方濫用。

程式執行結束時,系統會呼叫csingleton的靜態成員garbo的析構函式,該析構函式會刪除單例的唯一例項。

使用這種方法釋放單例物件有以下特徵:

在單例類內部定義專有的巢狀類;

在單例類內定義私有的專門用於釋放的靜態成員;

利用程式在結束時析構全域性變數的特性,選擇最終的釋放時機;

使用單例的**不需要任何操作,不必關心物件的釋放。

進一步的討論

但是新增乙個類的靜態物件,總是讓人不太滿意,所以有人用如下方法來重現實現單例和解決它相應的問題,**如下:

複製** **如下:

class csingleton

private:

singleton() {};

};使用區域性靜態變數,非常強大的方法,完全實現了單例的特性,而且**量更少,也不用擔心單例銷毀的問題。

但使用此種方法也會出現問題,當如下方法使用單例時問題來了,

singleton singleton = singleton :: getinstance();

這麼做就出現了乙個類拷貝的問題,這就違背了單例的特性。產生這個問題原因在於:編譯器會為類生成乙個預設的建構函式,來支援類的拷貝。

最後沒有辦法,我們要禁止類拷貝和類賦值,禁止程式設計師用這種方式來使用單例,當時領導的意思是getinstance()函式返回乙個指標而不是返回乙個引用,函式的**改為如下:

複製** **如下:

static singleton *getinstance()

但我總覺的不好,為什麼不讓編譯器不這麼幹呢。這時我才想起可以顯示的生命類拷貝的建構函式,和過載sbgybuc = 操作符,新的單例類如下:

複製** **如下:

class singleton

private:

singleton() {};

singleton(const singleton);

singleton & operate = (const singleton&);

};關於singleton(const singleton); 和 singleton & operate = (const singleton&); 函式,需要宣告成私用的,並且只宣告不實現。這樣,如果用上面的方式來使用單例時,不管是在友元類中還是其他的,編譯器都是報錯。

不知道這樣的單例類是否還會有問題,但在程式中這樣子使用已經基本沒有問題了。

優化singleton類,使之適用於單執行緒應用

singleton使用操作符new為唯一例項分配儲存空間。因為new操作符是執行緒安全的,在多執行緒應用中你可以使用此設計模板,但是有乙個缺陷:就是在應用程式終止之前必須手工用delete摧毀例項。否則,不僅導致記憶體溢位,還要造成不可**的行為,因為singleton的析構函式將根本不會被呼叫。而通過使用本地靜態例項代替動態例項,單執行緒應用可以很容易避免這個問題。下面是與上面的getinstance()稍有不同的實現,這個實現專門用於單執行緒應用:

複製** **如下:

csingleton* csingleton :: getinstance()

本地靜態物件例項inst是第一次呼叫getinstance()時被構造,一直保持活動狀態直到應用程式終止,指標m_pinstance變得多餘並且可以從類定義中刪除掉,與動態分配物件不同,靜態物件當應用程式終止時被自動銷毀掉,所以就不必再手動銷毀例項了。

**學習

複製** **如下:

//版本一

#include   

using namespace std;  

//單例類的c++實現  

class singleton  

;  

//構造方法實現  

singleton::singleton()  

singleton::~singleton()  

//初始化靜態成員  

/*singleton* singleton::instance=null;

singleton* singleton::getinstance()  

*/singleton* singleton::instance=new singleton;

singleton* singleton::getinstance()  

//seter && getter含數  

int singleton::getvar()  

void singleton::setvar(int var)  

//main  

void main()  

本文標題: c++中的單例模式介紹

本文位址: /ruanjian/c/93169.html

單例模式介紹

使用單例模式有乙個必要條件 在乙個系統要求乙個類只有乙個例項時才應當使用單例模式。單例模式又分為餓漢式和懶漢式。1.餓漢式 public class singleton 靜態工廠方法 public static singleton getinstance 單例類的乙個最重要的特點是類的構造器是私有的...

單例模式介紹

簡單來說就是建立物件時無論怎麼建立都只有乙個例項物件 介紹 只有在用到這個物件的時候才會去建立這個物件。存在問題 執行緒不安全,當使用多執行緒時會出現建立多個物件的情況。演示 public class bbb 建立靜態bbb物件 private static bbb bbb null 建立獲得bbb...

單例模式的介紹

單例的介紹 在專案的過程中存在著這樣特點的一些類,頻繁使用的物件,比如 的訪問記數器,資料庫的連線池,執行緒池等等方面只允許擁有乙個物件,允許擁有乙個例項。這樣的情況下會用到單例。單例模式的好處 1 對於頻繁使用的物件,可以省略建立物件所花費的時間,減少系統的開銷 2 由於new操作的次數減少,因而...