C 的單例模式

2022-05-01 21:48:08 字數 2908 閱讀 8139

單例模式可能是使用最廣泛的設計模式,其意圖是保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。

單例模式有很多實現方法,在c++中,甚至可以直接用乙個全域性變數做到這一點,但是這樣的**顯得很不優雅。《設計模式》一書中給出了一種很不錯的實現,定義乙個單例類,使用類的私有靜態指標變數指向類的唯一例項,並用乙個公有的靜態方法獲得該例項。

class

csingleton

static csingleton *m_pinstance;

public

:

static csingleton *getinstance()

};

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

csingleton* p1 = csingleton :: getinstance();

csingleton* p2 = p1->getinstance();

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

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

有經驗的讀者可能會問,m_pinstance指向的空間什麼時候釋放?更嚴重的問題是,該例項的析構函式什麼時候呼叫?

可以在程式結束時呼叫getinstance(),並對返回的指標呼叫delete操作。這樣這可以實現功能,但不僅醜陋,而且容易出錯。

乙個妥善的辦法是讓這個類自己知道在合適的時候自己刪除,或者說把刪除自己的操作掛在作業系統某個合適的點上。我們知道,程式在結束的時候,系統會析構所有的全域性變數。事實上,系統也會析構所有類的靜態成員變數,就像這些靜態成員也是全域性變數一樣。利用這個特性,我們可以在單例類中定義這樣乙個靜態成員變數,而它的唯一工作就是在析構函式中刪除單例類的例項。如下面**中的cgarbo類。

class

csingleton

static csingleton *m_pinstance;

class cgarbo //

它的唯一工作就是在析構函式中刪除csingleton的例項

};static cgarbo garbo; //

定義乙個靜態成員變數,程式結束時,系統會自動呼叫它的析構函式

public

:

static csingleton *getinstance()

};

類cgarbo被定義為csingleton的私有巢狀類,以防止該類在其他地方被濫用。程式執行結束時,系統會呼叫csingleton的靜態成員garbo的析構函式,該析構函式會刪除單例的唯一例項。

進一步討論,

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

class

csingleton

public

:

static csingleton &getinstance()

};

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

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

singleton singleton = singleton :: getinstance();

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

最後沒有辦法,我們要禁止類拷貝和類賦值,禁止程式設計師用這種方法來使用單例,比如返回乙個指標,

class

csingleton

public

:

static csingleton *getinstance()

};

可以直接讓編譯器不這麼幹嗎?這時我才想起可以顯示的宣告類拷貝的建構函式,和過載 = 操作符,新的單例類如下:

class

csingleton

csingleton(

const csingleton &);

csingleton & operator = (const csingleton &);

public

:

static csingleton &getinstance()

};

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

考慮到執行緒安全、異常安全,可以做以下擴充套件:

class

lock

~lock()

}; class

singleton;

singleton* singleton::pinstance = 0;

singleton*singleton::instantialize()

}return

pinstance;

}

之所以在instantialize函式裡面對pinstance 是否為空做了兩次判斷,因為該方法呼叫一次就產生了物件,pinstance == null 大部分情況下都為false,如果按照原來的方法,每次獲取例項都需要加鎖,效率太低。而改進的方法只需要在第一次 呼叫的時候加鎖,可大大提高效率。

C 單例模式

include using namespace std 單例類的c 實現 class singleton 構造方法實現 singleton singleton void singleton setvar int var main int main int argc,char argv return ...

C 單例模式

實現方式一 include template typename t class singleton boost noncopyable static void init private static pthread once t ponce statict value template typena...

C 單例模式

效率有點低,但是還算安全的單例模式,靜態成員實現方式 class singleton public static singleton getinstance singleton singleton getinstance unlock return m instance 內部靜態例項的懶漢模式,c ...