總體來說,雖然是基本話題,不過還是可以寫出一點點新意,也算是自己的代碼總結。
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_;
};
這樣使用起來就不必寫出完整的類名了