C 實現單例模式

2021-07-29 12:58:34 字數 4464 閱讀 2405

關於單例模式的相關資料和博文非常多,原因不僅僅在於它作為設計模式的重要性,也在於各大公司筆試面試題出現概率之高讓人乍舌。正因為如此,通過這篇博文的書寫,加深自己對單例模式的理解,以不變應萬變。

單例模式是一種常用的軟體設計模式。在它的核心結構中只包含乙個被稱為單例類的特殊類。通過單例模式可以保證系統中乙個類只有乙個例項而且該例項易於外界訪問,從而方便對例項個數的控制並節約系統資源。如果希望在系統中某個類的物件只能存在乙個,單例模式是最好的解決方案。

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

1. 由於單例模式在記憶體中只有乙個例項,減少了記憶體開支,特別是**乙個物件需要頻繁地建立、銷毀**時,而且建立或銷毀時效能又無法優化,單例模式的優勢就非常明顯。

2. 減少了系統的效能開銷,當**乙個物件的產生需要比較多的資源**時,如讀取配置、產生其他依賴物件時,則可以通過在應用啟動時直接產生乙個單例物件,然後永久駐留記憶體的方式來解決。

3. 避免對資源的多重占用。如避免對同乙個資源檔案的同時寫操作。

4. 單例模式可以在系統設定全域性的訪問點,優化和共享資源訪問。

1. 單例模式一般沒有介面,擴充套件困難。不利於測試。

1. 在整個專案中需要乙個共享訪問點或共享資料。

2.建立乙個物件需要消耗的資源過多,如要訪問io和資料庫等資源。

3. 需要定義大量的靜態常量和靜態方法的環境。

首先介紹一種最經典的實現方式

class singleton

public:

static singleton * getinstance() };

singleton* singleton::instance = null;

通過**我們便能夠清晰的了解到單例模式設計的思想,首先單例類沒有公開的構造器,其他類不能自行將其實例化得到乙個例項,而必須通過它的靜態方法getinstance()去建立乙個例項。

那麼我們該如何建立乙個單例呢,有以下三種方式,這三種方式大致相同,都是通過getinstance()方法獲取例項。

singleton *a = singleton::getinstance();

singleton *b = a->getinstance();

singleton &c = *singleton::getinstance();

那麼上面的實現方式有缺陷嗎?當然有,而且當你在面試或者筆試中寫出該實現方式時,面試官一定不會滿意的。

首先我們很容易發現,instance指向的空間何時釋放,該例項的析構函式何時呼叫?如果我們想在該類析構時進行一些操作,比如關閉檔案流等。上面實現的單例並不能滿足這些要求。因此我們需要一種方法,讓該例項能夠自動刪除自己。

熟悉c++的知道,在程式執行結束時,會自動**所有全域性變數和靜態變數,這些變數儲存在全域性/靜態儲存區。而堆區,就是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般乙個new就要對應乙個delete。如果程式設計師沒有釋放掉,那麼在程式結束後,作業系統會自動**。利用這個特性,我們可以在該單例中定義這樣乙個靜態成員變數,該變數在其析構函式中刪除單例類的例項,從而達到**記憶體的目的。正如下面**中的cgarbo類。

class singleton

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

class cgarbo

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

static cgarbo garbo;

public:

static singleton * getinstance() };

singleton* singleton::instance = null;

singleton::cgarbo singleton::garbo;

我們可以寫一段測試**來檢視是否成功刪除單例的例項,測試**如下,增加了單例類的析構函式

#includeusing namespace std;

class singleton

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

class cgarbo

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

static cgarbo garbo;

public:

static singleton * getinstance()

~singleton() };

singleton* singleton::instance = null;

singleton::cgarbo singleton::garbo;

int main()

執行結果:

delete success

在前面實現的經典單例模式中,例項刪除問題已經解決了,但還不夠。乙個很嚴重的問題就是,該實現方式時執行緒不安全的。假設單例還未初始化,有兩個執行緒同時呼叫getinstance方法,這時執行 instance == null 肯定為真,然後兩個執行緒都初始化乙個單例,最後得到的指標並不是指向同乙個地方,不滿足單例類的定義了。

所以為了滿足執行緒安全,我們需要做一些微小的工作,使用了linux的互斥鎖,在建構函式中初始化。

class singleton

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

class cgarbo

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

static cgarbo garbo;

static pthread_mutex_t mutex;

public:

static singleton * getinstance()

return instance;

}};singleton* singleton::instance = null;

singleton::cgarbo singleton::garbo;

pthread_mutex_t singleton::mutex;

解決了執行緒問題後,才算是乙個完整的單例模式。接下來介紹的只是不同的實現方式,大同小異,所要考慮的也不外乎是執行緒安全和記憶體管理等問題。

有關單例模式的實現方式分為兩種:懶漢模式餓漢模式

懶漢模式

顧名思義,懶漢模式就是程式足夠懶,只有在需要使用例項時候才建立例項,是一種以時間換空間的做法。上面的經典實現即懶漢模式,只有在getinstance的時候才新建例項。經典實現中需要考慮執行緒安全和記憶體釋放,這裡再介紹一種懶漢實現方式,不需要考慮記憶體釋放問題,簡化了**。

class singleton

static pthread_mutex_t mutex;

public:

static singleton * getinstance() };

pthread_mutex_t singleton::mutex;

相信你一眼就看出,這種改進只不過是使用了區域性靜態變數,然後返回改變量的引用。這麼乙個微小的改動就能節省很多的**。

餓漢模式

模擬於懶漢模式,餓漢模式就是程式非常餓,在剛開始就初始化了乙個例項,是一種以空間換時間的做法。正是由於該特性,懶漢模式不需要考慮執行緒安全的問題,但是依舊需要考慮例項刪除的問題。

class singleton

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

class cgarbo

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

static cgarbo garbo;

public:

static singleton * getinstance() };

singleton* singleton::instance = new singleton;

singleton::cgarbo singleton::garbo;

無論是懶漢還是餓漢還是什麼其他的實現方式,除了基本的單例模式的屬性以外,需要考慮的無外乎執行緒安全和記憶體管理(例項刪除)的問題,正確的處理好這些要點,那麼你的單例模式就一定是合格的。

C 實現單例模式

給所需要進行單例的類ctest的建構函式宣告為private或者protected 防止在類外隨意生成ctest的物件 然後宣告乙個靜態成員變數 instance 乙個靜態成員函式getinsance staticctest getinstance staticctest instance 靜態成員...

C 實現單例模式

ifndef singleton h define singleton h include include using namespace std class locker inline locker inline void lock inline void unlock private pthre...

C 實現單例模式

class singleton 私有建構函式 singleton const singleton 拷貝建構函式,只宣告不定義,這要當使用者或友元想要拷貝構造該類的已存在例項時會出錯。singleton operator const singleton 賦值運算子,只宣告不定義,作用同上 public...