天天看點

RAII的一些實作

總體來說,雖然是基本話題,不過還是可以寫出一點點新意,也算是自己的代碼總結。

RAII實作和智能指針一樣,甚至可以了解為定制shared_ptr的Dx為資源釋放方法即可。

不過對于個人來說,還是喜歡用意圖明确,簡單,專用化的代碼。

個人工作中用過兩種類型的,一種是Windows上各種HANDLE,HMODULE,Hxxx的釋放,于是寫了一些通用的代碼:

template<typename T>
	struct destory_t;

#define DESTORY_IMPL(type, method)	\
	template<>\
	struct destory_t<type>\
	{\
		static void destory(type h)\
		{\
			method(h);\
		}\
	};

	DESTORY_IMPL(HANDLE, CloseHandle)
	DESTORY_IMPL(HMODULE, FreeLibrary)
	
	template<typename T, template <typename U> class D = destory_t>
	struct smart_handler 
	{
		smart_handler(T handler)
			: handler_(handler)
		{}

		~smart_handler()
		{
			D<T>::destory(handler_);
		}
		operator T() const
		{
			return handler_;
		}

		T handler_;
	};

	typedef smart_handler<HANDLE> SHandle;
	typedef smart_handler<HMODULE> SModule;
           

這樣就不擔心忘記關閉啥的了,本質和smartptr一樣,隻不過更加專用。這裡沒用指針是因為windows下的各種句柄本來有指針語意,如果要照搬還得考慮下。

PS.網上很多人說這種代碼是否有禁止copy是XX試金石,我的看法是,對于這樣的類使用assign,copy ctor基本是故意找茬的代碼,就如所謂string的assign檢查自指派一樣(雖然還是得寫,或用臨時對象來實作)。

另外一種是XXGuard,這樣的情況也比較多,比如各種加鎖,解鎖。

最基本情況,假設有兩種鎖:

struct critical_section_lock
	{
		void lock() { printf("critical_section_lock.lock()\n"); }
		void unlock() { printf("critical_section_lock.unlock()\n"); }
	};

	struct spin_lock
	{
		void lock() { printf("spin_lock.lock()\n"); }
		void unlock() { printf("spin_lock.unlock()\n"); }
	};
           

其中,ctor,dtor分别是對内部資料結構的建立和删除,不予附上

最基本的寫法是對兩個lock分别寫自己的guard。當然模版是更好的實作,如:

template<typename T>
	struct lockguard
	{
		lockguard(T& lock)
			: lock_(&lock)
		{
			lock_->lock();
		}
		~lockguard()
		{
			lock_->unlock();
		}

		T* lock_;
	};
           

使用起來是這樣的:

critical_section_lock g_cslock;
	spin_lock	g_splock;
	void main()
	{
		lockguard<critical_section_lock> o(g_cslock);
	}
           

其實也可以了,但一直覺得把完整模版參數類名寫出來好麻煩,當然C++11的auto表示沒壓力。

設計思路:

1.因為lockguard是模版類,使用時必須指明類型名。是以首先必須要使得它不是模版類

2.構造函數能接受各種類型,是以構造函數得是模版函數

3.由于要儲存實際的鎖的指針(析構解鎖用),而整個類不是模版類,是以這個指針類型得是普通指針

4.加解鎖時為了能使用這個指針的lock函數編譯過,是以這個指針得是接口類的指針

5.有以上思路後,最後需要的是用模版類實作這個接口類的方法

這樣的思路其實也就是boost::any以及loki::function中的慣用手法。。。

最終代碼:

struct ILock
	{
		virtual void lock() = 0;
		virtual void unlock() = 0;	
	};

	template<typename T>
	struct TLock : public ILock
	{

		TLock(T* lock)
		{
			lock_ = lock;
		}

		void lock() { lock_->lock(); }
		void unlock() { lock_->unlock(); }

		T*	lock_;
	};

	struct lockguard
	{
		template<typename T>
		lockguard(T& lock)
			: impl_(new TLock<T>(&lock))
		{
			impl_->lock();
		}
		~lockguard()
		{
			impl_->unlock();
		}

		auto_ptr<ILock>	impl_;	
	};
           

這樣使用起來就不必寫出完整的類名了