C Singleton設計模式思考

2021-09-25 15:09:01 字數 1797 閱讀 4018

先說重點,我覺得網上很多文章的singleton實現都有些老。

我認為只需要這麼寫。

class singleton1

public:

static singleton1& get_instance()

};

singleton模式的核心特點就是把建構函式設為私有。這樣就能保證沒有例項能被建立。那如何僅建立乙個例項呢?在類內(類外其實也行)寫個get_instance()函式,這個函式必須是靜態的(類外不必),因為它在類內,類內只有靜態的(成員函式或成員變數)才會被類所共享,什麼叫共享?你用這個類建立多個例項,每個例項的成員變數或者成員函式都是屬於自己例項的。再簡單點舉個例子 :

class a

static void c() };

int main()

舉的是成員函式的例子,成員變數也是同理。那麼繼續說,靜態get_instance()方法中建立乙個靜態例項,靜態例項保證這個例項永遠只有乙個。那到底是如何保證的呢?這就需要涉及記憶體分配了(詳見這篇部落格)。get_instance()方法返回引用,在能使用引用的情況下盡量避免使用指標,引用與指標最大的區別在於引用不能為空,乙個引用必然有它引用的物件,但乙個指標可以為空,空指標總會給人不好的聯想,但在這個例子中好像並無大礙,第二大區別就是引用宣告的同時就必須得定義,並且它將不能更改引用其他的物件。(這兩大特點其實很好理解,因為建立乙個引用實際上就是為乙個物件建立乙個別名。)

這兩個區別好像都不足以說服你在實現singleton中引用比指標好在**,那你在想想如果用指標來實現,大概應該是這樣吧

class singleton2

public:

static singleton2* get_instance()

return p;

}};

你或許突然想到了問題所在:光從freestore中new了記憶體,沒有delete掉啊?。這就需要再寫個destroy方法,在其中delete。然後在真正使用這個singleton例項時,使用後最後還得呼叫個destroy,忘記呼叫了就會導致記憶體洩漏。這就是真正的麻煩所在。而且new還是從自由儲存區上分配的,比從棧上分配速度慢,何苦用哉。那為什麼還是有的文章中這麼用了呢(據說好像設計模式書裡也是這麼用的)。我想原因或許是考慮到多執行緒了吧。在多執行緒併發條件下,各個執行緒都會認為自己是第乙個遇見static的「人」,並爭搶著初始化,會導致data race。所以你就不能在get_instance方法中靠建構函式直接static乙個例項,而是需要保護初始化過程。

有的文章中保護的方式還用到了聲名狼藉的double check lock(《c++併發程式設計實戰》)

雙重檢驗鎖是一種不好的方式,其實這些我也都是從這本書上才知道的。它潛在著一種競爭關係詳見這篇文章。跳過所有細節,我要說的重點就是

c++11以後的編譯器在多執行緒的情況下使用static不會產生race condition。

初始化及定義完全在乙個執行緒中發生,並且沒有其他執行緒可在初始化完成前對其進行處理。《c++併發程式設計實戰》

也就是說根本不需要保護資料的初始化過程,按我最初給的**那麼寫就行。如果以後真的需要用到相同的singleton但是需要多種不同的型別,填個template就完了,要是還需要繼承(真的會需要繼承麼)就把建構函式放protected裡就完了。

C Singleton單例模式

version6 include using namespace std templateclass singleton protected 保護型別,因為子類繼承的時候要呼叫父類建構函式,寫成public肯定不行,寫成private子類就無法訪問,就需要寫friend class manager了...

C Singleton單例模式

實現單例步驟 1.建構函式私有化 2.增加靜態的 私有的當前類的指標變數 3.提供乙個靜態的公有介面,可讓使用者獲得單例物件 1 include2 3using namespace std 45 classa6 9public 10 static a getinstance 步驟3 1114 pri...

Leader Follower 程序池設計思路

看了 url 的分析文章 url 之後,覺得裡面的圖非常好地描述了 apache 的結構。也嘗試用 visio 畫一下 url 的結構。對圖中各個部分的說明 1.masterserver 通過 fork 建立 processmanager processpool 作為 processmanager ...