分享
 
 
 

VC及C++的智能指针应用分析

王朝vc·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

前段时间,在查控件的内存泄露时,最终找出一个错误:在使用XMLDom(COM)时,由于重复使用某接口指针前未释放Dispatch指针(Release),而导致内存泄露,而此类错误(如同BSTR类型的泄漏),VC的调试器和Bondcheck均无能为力。解决办法,似乎只有细心一途。

但只要稍稍仔细看看,就可发现,实际上如果正确使用VC提供的智能指针,是可以避免此问题的。

另外,一直为Java程序员津津乐道的内存使用无需管理的优势,一直知道用C++的智能指针可以模拟。但一直没实际动手做过,趁此分析之机,用C++简单包装了一个。反正粗看之下,可以达到与Java类似的效果,当然,C++的对象更高效且节省内存。

就以上所提到的,时间关系,我只能简单罗列几点,代码应该是正确的(但未检查)。前后文没什么逻辑关系,但如果要进一步应用C++的智能指针,相信会起到抛砖引玉之效。

一:关于纠错,MFC和ATL中智能指针的应用

1:在Windows中如何方便的查看当前进程使用的内存。

虽然代码简单,但对纠错时有大用处,不用不停的通过切换任务管理器来查看内存使用。代码如下:

UINT C_BaseUtil::getProcessMemoryUsed()

{

UINT uiTotal = 0L;

HANDLE hProcess = ::GetCurrentProcess();

PROCESS_MEMORY_COUNTERS pmc;

if(::GetProcessMemoryInfo(hProcess,&pmc,sizeof(pmc)))

uiTotal = pmc.WorkingSetSize;

return uiTotal;

}

注意:由于内存使用会是一个不稳定的过程,所以,需要在程序稳定时进行调用,才能准确。

2:在使用Com的Dispatch指针时,如果不使用COM智能指针,容易出现的错误。

2.1:忘记在所有出口释放指针。

如:

IXMLDOMDocument *pDoc = NULL;

CoCreateInstance(...)

……

pDoc->Release();

错误:如果中间代码发生异常,则pDoc未能正常释放,造成内存泄露。

2.2:重复使用同一指针变量,导致中间生成的Dispatch指针未能释放。

IXMLDOMNode *pNode = NULL;

if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &pNode)) || pNode==NULL)

throw(_T("selectSingleNode failed!"));

if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &pNode)) || pNode==NULL)

throw(_T("selectSingleNode failed!"));

错误:pNode未释放就开始第二次调用,造成内存泄露。或者类似pNode = pNode2的这种写法,也随手就出问题了。必须调用if(pNode) {pNode->Release();pNode=NULL;}

3:使用MFC提供的Com智能指针解决上述问题。

注意:可通过查看源码,看到#import生成的智能指针的原型是_com_ptr_t。

3.1:

IXMLDOMDocumentPtr docPtr = NULL;

docPtr.CreateInstance(...)

……

OK,这下不会有问题了,因为docPtr在析构时会有正确的释放处理。

3.2:

IXMLDOMNodePtr nodePtr = NULL;

if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &nodePtr)) || nodePtr==NULL)

throw(_T("selectSingleNode failed!"));

if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &nodePtr)) || nodePtr==NULL)

throw(_T("selectSingleNode failed!"));

OK,不会出错了,因为_com_ptr_t重载了&操作符,在取指针时,有如下操作,嘿。

Interface** operator&() throw()

{

_Release();

m_pInterface = NULL;

return &m_pInterface;

}

3.3: nodePtr = nodePrt2 ,也不会有问题:

仔细查看源码,在=操作符中会调用Attach,而Attach的做法是:会先调用_Release();

3.4:再看看值传递:拷贝构造函数如下

template<> _com_ptr_t(const _com_ptr_t& cp) throw()

: m_pInterface(cp.m_pInterface)

{

_AddRef();

}

嗯,也不会有问题。

3.5:最后我们也总结一下使用COM智能指针时的注意事项:

3.5.1:不要在Com智能指针的生命期如果在::CoUninitailize之后,那请在调用::CoUninitailize之前,强制调用MyComPtr = NULL;达到强制释放的目的。否则会出错。

3.5.2:不要混用智能指针和普通Dispatch指针,不要调用MyComPtr->Release(),这违背智能指针的原意,会在析构时报错。

4:使用ATL提供智能指针:CComPtr或是CComQIPtr.

如果不使用MFC框架,要自已包装IDispatch,生成智能指针,还可以使用ATL提供的智能指针。

查看源码,并参照《深入解析ATL》一书,发现实现与_com_ptr_t大同小异,效果一致。

二:引申一下,我们来看看C++的智能指针

1:说到智能指针,我们一定要看看标准C++提供的auto_ptr。

而auto_ptr的使用是有很多限制的,我们一条一条来细数:

1.1:auto_ptr要求一个对象只能有一个拥有者,严禁一物二主。

比如以下用法是错误的。

classA *pA = new classA;

auto_ptr<classA> ptr1(pA);

auto_ptr<classA> ptr2(pA);

1.2:auto_ptr是不能以传值方式进行传递的。

因为所有权的转移,会导致传入的智能指针失去对指针的所有权。如果要传递,可以采用引用方式,利用const引用方式还可以避免程序内其它方式的所有权的转移。就其所有权转移的做法:可以查看auto_ptr的拷贝构造和=操作符的源码,此处略。

1.3:其它注意事项:

1.3.1:不支持数组。

1.3.2:注意其Release语意,它没有引用计数,与com提供的智能指针不同。Release是指释放出指针,即交出指针的所有权。

1.3.3:auto_ptr在拷贝构造和=操作符时的特珠含义决定它不能做为STL标准容器的成员,

好了,看了上面的注意事项,特别是1.3.3,基本上可以得出结论,在实际应用场合,auto_ptr基本上是没什么应用价值的。

2:如何得到支持容器的智能指针。

我们利用auto_ptr的原型,制作一个引用计数的智能指针,则时让它支持STL容器的标准。

实现代码很简单,参照了《C++标准程序库》中的代码,关键代码如下:

template<class T>

class CountedPtr {

T * ptr;

long * counter;

public:

//构造

explicit CountedPtr(T* p = NULL)

:ptr(p),count(new long(1){}

//析构

~CountedPtr() {Release();}

//拷贝构造

CountedPtr(cont CountedPtr<T>& p)

:ptr(p.ptr),count(p.count) {++*counter;}

//=操作符

CountedPtr<T>& operator= (const CountedPtr<T>& p) {

if(this!=&p) {

Release(); ptr=p.ptr; counter=p.counter;++*counter;

}

return *this;

}

//其它略

....

private:

void Release() {

if(--*counter == 0) {

delete counter;

delete ptr;

}

}

}

好了,这样,当复制智能指针时,原指针与新指针副本都是有效的,这样就可以应用于容器了。

现在,通过CountedPtr包装的C++对象,是不是和Java的对象类似了呢,呵呵。

只要再加上一些必要的操作符,它就可以作为容器中的共享资源来使用了。

石头 于2005-12-07 19:00

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有