1. 程式人生 > >C++單例模式的模板基類

C++單例模式的模板基類

單例模式是很常用的設計模式,如果希望系統中某個類的物件只能有一個或者有一個就夠了,那麼便可以採用單例模式來解決。
下面用C++實現一個單例模板類,那麼其他的類只需繼承它,便可以成為單例類。
本例中使用了 CMutex類,是考慮多執行緒的情況,這個類的定義請參見筆者的另一篇部落格《C++簡單封裝互斥量》,

連結 http://blog.csdn.net/kentzhang_/article/details/48180865


程式碼如下:

BaseSingleton.h

/************************************************************************* 
    > File Name: BaseSingleton.h 
    > Author: KentZhang 
    > Mail: 
[email protected]
> Created Time: Wed 04 Sep 2015 09:02:12 PM CST ************************************************************************/ #ifndef __BASE_SINGLETON_H__ #define __BASE_SINGLETON_H__ #include<new> #include "CMutex.h" template<typename T> class BaseSingleton { public: static T *Instance() { if(NULL != m_Instance) { return m_Instance; } m_Mutex.Lock(); if(NULL != m_Instance) { m_Mutex.UnLock(); return m_Instance; } m_Instance = new(std::nothrow) T(); m_Mutex.UnLock(); return m_Instance; } BaseSingleton(){} virtual ~BaseSingleton(){} private: static T *m_Instance; static CMutex m_Mutex; }; template<typename T> T *BaseSingleton<T>::m_Instance = NULL; template<typename T> CMutex BaseSingleton<T>::m_Mutex; #endif


測試用例:

TestSingleton.cpp

/************************************************************************* 
    > File Name: TestSingleton.cpp 
    > Author: KentZhang 
    > Mail: [email protected] 
    > Created Time: Wed 04 Sep 2015 09:21:10 PM CST 
 ************************************************************************/  

#include "BaseSingleton.h"
#include <string>
#include <iostream>
class TestSingleton : public BaseSingleton<TestSingleton>
{
private:
	TestSingleton(){}; //建構函式,拷貝建構函式,宣告為私有,不允許在類外建立物件,保證該類只有一個物件
	TestSingleton(const TestSingleton&){};
public:
	~TestSingleton(){};
	void Show(){std::cout<<"I am a singleton."<<std::endl;};
	friend BaseSingleton<TestSingleton>; //由於建構函式為私有,而基類必須呼叫,所以這裡宣告基類為友元類
};

int main()
{
	//TestSingleton ts; //這裡編譯報錯,顯然是不允許在類外建立物件 

	TestSingleton* p1 = TestSingleton::Instance();
	p1->Show();
	std::cout<<"p1="<<p1<<std::endl;
	
	//TestSingleton ts(*p1); //這種方式,同樣報錯

	TestSingleton* p2 = TestSingleton::Instance();
	p2->Show();
	std::cout<<"p2="<<p2<<std::endl;

	TestSingleton* p3 = TestSingleton::Instance();
	p3->Show();
	std::cout<<"p3="<<p3<<std::endl;

	return 0;
}

編譯:g++   CMutex.cpp   TestSingleton.cpp   -lpthread   -o  main

執行:./main

I am a singleton.
p1=0x82ad028
I am a singleton.
p2=0x82ad028
I am a singleton.
p3=0x82ad028

在本例中,有個明顯的缺陷,即那個靜態的單例指標才會何時delete,當然delete會自動呼叫它的解構函式完成終止化操作。

如果手動判斷delete,但是在大多時候,並不能準確的判斷單例何時不再使用,另一方面的單例類在記憶體中只有一個物件,

並不會造成記憶體洩露,因此大多數時候單例物件的析構是在程式結束的時候完成的。

上面的單例物件是在堆上分配的,需要手動delete,下面採用在靜態區分配物件,單例基類修改如下:

BaseSingleton.h

#ifndef __BASE_SINGLETON_H__
#define __BASE_SINGLETON_H__
#include<new>
#include "CMutex.h"

template<typename T>
class BaseSingleton
{
	public:
		static T *Instance()
		{
			if(NULL != m_Instance)
			{
				return m_Instance;
			}

			m_Mutex.Lock();
			if(NULL != m_Instance)
			{
				m_Mutex.UnLock();
				return m_Instance;
			}

			//m_Instance = new(std::nothrow) T();
			static T tInstance;  //這裡採用靜態區域性變數,保證程式執行時一直存在,程式結束時,會自動析構這個靜態變數
			m_Instance = &tInstance;
			
			m_Mutex.UnLock();
			return m_Instance;
		}


		BaseSingleton(){}
		virtual ~BaseSingleton(){}

		static T *m_Instance;
		static CMutex m_Mutex;
};

template<typename T>
T *BaseSingleton<T>::m_Instance = NULL;
template<typename T>
CMutex BaseSingleton<T>::m_Mutex;

#endif


由於筆者的水平有限,出錯在所難免,懇請讀者拍磚指正,謝謝閱讀