设为首页 加入收藏

TOP

有效的使用和设计COM智能指针――条款10(一)
2014-11-23 23:11:49 来源: 作者: 【 】 浏览:4
Tags:有效 使用 设计 COM 智能 指针 条款

条款10:尽量减少智能指针和接口指针的混用
在开始一节之前,让我们先来看一个例子:

view plaincopy to clipboardprint void func(void)
{
ICalculator *pCalculator = NULL;
CComPtr pCalculator = NULL;
hrRetCode = CoCreateInstance( //在这里创建COM组件,引用计数为1。
CLSID_CALCULATOR,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICALCULATOR,
(void **)&pCalculator
);
assert(hrRetCode);
spCalculator = pCalculator; //将创建好的组件交给智能指针让其管理引用计数
//赋值运算符会再次调用AddRef()增加引用计数
spCalculator->DoSomething();
} //调用Release()后引用计数不为0,发生了资源泄漏。
void func(void)
{
ICalculator *pCalculator = NULL;
CComPtr pCalculator = NULL;
hrRetCode = CoCreateInstance( //在这里创建COM组件,引用计数为1。
CLSID_CALCULATOR,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICALCULATOR,
(void **)&pCalculator
);
assert(hrRetCode);
spCalculator = pCalculator; //将创建好的组件交给智能指针让其管理引用计数
//赋值运算符会再次调用AddRef()增加引用计数
spCalculator->DoSomething();
} //调用Release()后引用计数不为0,发生了资源泄漏。
如果不仔细观察,可能很难发现上述例子中存在一个资源泄漏问题。但细致的分析一下,可以发现上述代码中CoCreateInstance中会调用一次接口的AddRef()。而在智能指针赋值过程中又调用了一次AddRef()。但智能指针析构时只有一次Release()调用,因此,这个时候COM的引用技术没有归零,从而不会析构。但函数结束后,没有任何指针能够再次访问到COM组件。因此它在内存中“游离”了,资源泄漏也就产生了。

问题的关键在于接口指针与智能指针混合使用了。而在最后忘记调用接口指针的Release()从而导致了资源泄漏。

可能你会在此函数最末尾补上一句“pCalculator->Release()”,但非常不推荐你这样做。因为我们引入智能指针的目的就是为了尽可能简化我们的开发。若是将智能指针与接口指针混合使用,则会要话费更多的时间来思考引用计数问题。

因此最好的解决办法是将接口指针从函数中完全剔除出来。上述函数完全可以由一下这个例子来完成:

view plaincopy to clipboardprint void func(void)
{
CComPtr pCalculator = NULL; //只有智能指针
hrRetCode = pCalculator .CoCreateInstance(CLSID_CALCULATOR,);//引用计数为1
assert(hrRetCode);
spCalculator->DoSomething();
} //调用Release()后引用计数为0,资源正确的被释放了
void func(void)
{
CComPtr pCalculator = NULL; //只有智能指针
hrRetCode = pCalculator .CoCreateInstance(CLSID_CALCULATOR,);//引用计数为1
assert(hrRetCode);
spCalculator->DoSomething();
} //调用Release()后引用计数为0,资源正确的被释放了

混用智能指针会使得代码引用计数难以琢磨,因此我们不应当在代码中混用智能指针与接口指针。

但凡是都有例外,接口指针并非没有用武之地。而且你已经在之前的章节中见到了这个问题。我们在函数参数传递过程中仍然使用了接口指针。

view plaincopy to clipboardprint void SomeApp( IHello * pHello )
{
CComPtr pCopy = pHello;
OtherApp();
pCopy->Hello();
}
void SomeApp( IHello * pHello )
{
CComPtr pCopy = pHello;
OtherApp();
pCopy->Hello();
}
你可能还会有个疑惑,为什么SomeApp( IHello * pHello )这个函数中的参数pHello不使用智能指针呢?

将智能指针放置到函数参数中这种做法并非不行,而是出于以下考虑我们选择了接口指针作为参数传递的类型:

1.如果使用了智能指针,那么此接口将无法在IDL文件中描述。

2.使用智能指针作为参数传递会增加接口的复杂度,造成理解上的困难。

3.使用如果使用第三方的智能指针作为参数的类型,则发布接口的时候需要将此智能指针的实现连同接口一起发布出去。若用户得不到此智能指针的实现,则无法使用此接口。

4.智能指针在传递过程中会产生更大的开销,从而降低程序的性能。

……

若智能指针出现在函数返回值之中,则危害会更大。试想一下如下代码,将会产生何种后果?

view plaincopy to clipboardprint CComPtr GetView(int nIndex)
{
CComPtr spView = NULL;
spView .CreateInstance(CLSID_MYCOMPONENT);
return spView ;
}
CComPtr GetView(int nIndex)
{
CComPtr spView = NULL;
spView .CreateInstance(CLSID_MYCOMPONENT);
return spView ;
}
但外面的调用过程如果是这样呢?

view plaincopy to clipboardprint IView *pIView = NULL;
pIView = GetView();
pIView->DoSomething();
IView *pIView = NULL;
pIView = GetView();
pIV

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇有效的使用和设计COM智能指针――.. 下一篇有效的使用和设计COM智能指针――..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: