在Windows編程中,GDI資源的泄露一直是需要引起C++程序員的高度關(guān)注,一不小心,就會在函數(shù)的中途正常退出或者中途拋出異常退出的地方遺忘掉釋放前面申請的資源。本人也曾多次碰到這種問題,查閱了網(wǎng)上的資料,總是不能得到滿意的解決。最近看了下boost中的庫,才略有收獲,也算是拋磚引玉吧。
要想解決上面的問題,就必須實現(xiàn)資源的自動釋放,類的析構(gòu)函數(shù)正好可以滿足此要求,就象標(biāo)準(zhǔn)庫中智能指針就是這么實現(xiàn)的,但問題在于我們的參數(shù)個數(shù),參數(shù)類型的不確定性。雖然重載和模板可以解決此問題(這也是我在網(wǎng)上看到的解決方法),但模板類的參數(shù)不具備自動推導(dǎo)能力(經(jīng)傳入成員函數(shù)參數(shù)值推導(dǎo)出模板參數(shù)類型),而且過多的模板偏特化也不是我所擅長的,最主要是代碼的移植性無法保證。
本文主要利用的boost中的bind庫,覺得仿函數(shù)的功能跟自己當(dāng)前的需求不遠(yuǎn)了,因為它們的共同點有:
1. 可以接收任意多個模板參數(shù)(沒有具體驗證,至少是9個吧),
2. 可以利用函數(shù)對模板參數(shù)類型的推導(dǎo)能力,省去了參數(shù)類型的指定。
唯一不同的是bind后的仿函數(shù)是立即執(zhí)行,不能具有類的析構(gòu)函數(shù)自動執(zhí)行的優(yōu)點。目前需要解決的問題是推遲執(zhí)行期,也既把operator()函數(shù)移到析構(gòu)函數(shù)中執(zhí)行,這就需要保存boost::bind(....)返回的對象,通過類的構(gòu)造函數(shù)去保存,然后在析構(gòu)函數(shù)中執(zhí)行operator()就可以了。
思路是出來了,但問題是boost::bind(...)函數(shù)返回的類型不確定,對象通過類模板是可以保存,但類沒有自動推導(dǎo)能力,還是無法實現(xiàn),這里我就利用了boost::any的原理,正好解決了此問題,而且它也可以用于函數(shù)的延遲執(zhí)行。詳見以下使用方法:
步驟1: 實現(xiàn)類似于boost:;any的類,主要完成資源的自動釋放。實現(xiàn)如下:
//SrcRelease.h頭文件
1
#ifndef _SRCRELEASE_INC_
2
#define _SRCRELEASE_INC_
3
4
class CSrcRelease
5

{
6
public:
7
template<typename T>
8
CSrcRelease(const T & value)
9
: m_pHelder(new Helder<T>(value))
10
{
11
}
12
13
~CSrcRelease()
14
{
15
delete m_pHelder;
16
}
17
18
private:
19
class IHelder
20
{
21
public:
22
virtual ~IHelder()
{}
23
};
24
25
template<typename T>
26
class Helder : public IHelder
27
{
28
public:
29
Helder(const T & value)
30
: held(value)
31
{
32
}
33
~Helder()
34
{
35
held();
36
}
37
38
public: // representation
39
T held;
40
};
41
42
IHelder* m_pHelder;
43
};
44
45
#endif //_SRCRELEASE_INC_
46
步驟2: 下載boost庫,因為只用到了boost::bind庫,所以無需編譯. 將頭文件目錄加入vs2005中。
步驟3: 客戶端調(diào)用
//main.cpp
1
#include "SrcRelease.h"
2
#include <iostream>
3
#include <Windows.h>
4
#include <boost/bind.hpp>
5
#include <cassert>
6
7
void _stdcall InvokeStr(const char* szValue)
8

{
9
std::cout<<szValue<<std::endl;
10
}
11
12
bool _stdcall InvokeStr(const char* szValue, int a, int b)
13

{
14
std::cout<<szValue<<"\ta: "<<a<<"\tb: "<<b<<std::endl;
15
return true;
16
}
17
18
int main()
19

{
20
//由于API都是_stdcall調(diào)用,而vs2005環(huán)境都是默認(rèn)_cdecl,所以需要修改vs2005環(huán)境
21
HBITMAP hBitmap=reinterpret_cast<HBITMAP>(LoadImage(NULL, L"test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
22
assert(hBitmap!=NULL);
23
CSrcRelease aBitmapRelease(boost::bind(&DeleteObject, hBitmap));
24
25
std::cout<<"Invoke Outer Before"<<std::endl;
26
CSrcRelease aRelease(boost::bind(&InvokeStr, "Invoke Outer After", 8, 5));
27
28
{
29
std::cout<<"Invoke Inner Before"<<std::endl;
30
CSrcRelease aRelease(boost::bind(&InvokeStr, "Invoke Inner After"));
31
std::cout<<"Invoke Inner Middle"<<std::endl;
32
}
33
34
std::cout<<"Invoke Outer Middle"<<std::endl;
35
return 0;
36
}
以上代碼在winxp+vs2005下測試通過,如有疑問,歡迎聯(lián)系:
ietj@mail.21cn.com 嘵月刀
2008.3.5