2013-11-15 61 views
3

我最近看到的智能指针和他们的陷阱一个PowerPoint,它有这个幻灯片(几乎没有评论或解释:此智能指针使用有什么问题?

在背景:特别是_com_ptr_t,智能指针的COM接口,处理的AddRef /释放如由_COM_SMARTPTR_TYPEDEF宏创建*


错误:

IObjectPtr spObj; 
for (int i(0); i<MAX; i++) 
{ 
    //passed as actual , no release of previous ptr value 
    spOtherObj->get_Obj(&spObj); 
} 

下一张幻灯片声称,它是好的,如果你把spObj循环的范围内:


右:

for (int i(0); i<MAX; i++) 
{ 
    IObjectPtr spObj; 
    //passed as actual , no release of previous ptr value 
    spOtherObj->get_Obj(&spObj); 
} 

我研究这个,仍然无法弄清楚他们在说什么。
第一个问题与第二个问题解决了什么问题?


我猜,在更全面的背景下,正确/错误代码是这样:
虽然我可能是错误的,我的假设

_COM_SMARTPTR_TYPEDEF(ICalendar, __uuidof(ICalendar)) 

void get_Calendar(ICalendarPtr* pCalendar) 
{ 
    *pCalendar.CreateInstance(__uuidof(Calendar));   
} 

void WrongMethod(void) 
{ 
    ICalendarPtr spCalendar; 
    for (int i(0); i<MAX; i++) 
    { 
     //passed as actual , no release of previous ptr value 
     get_Calendar(&spCalendar); 
    } 
} 
+1

它也没有帮助,没有上下文来说明get_Obj是在做什么。 –

+0

指针始终是智能的;) – lordkain

+1

这是关于COM对象的[_com_ptr_t](http://msdn.microsoft.com/en-us/library/vstudio/417w8b3b.aspx)智能指针的上下文。 – abelenky

回答

7

这最有可能是指ATL::CComPtr而不是_com_ptr_t

问题是,CComPtr::operator&返回被包装的指针的地址,但不释放它,因此如果它被声明在循环之外,假定被包装的接口不是NULL,则泄漏对象。

实施承认这个事实,这是从ATL头文件,包括注释直接复制:

//The assert on operator& usually indicates a bug. If this is really 
//what is needed, however, take the address of the p member explicitly. 
T** operator&() throw() 
{ 
    ATLASSERT(p==NULL); 
    return &p; 
} 

_com_ptr_t修复了这个问题,并且一般使用起来更加方便,所以应该首选是适用的。

+0

非常好的答案。如果你是对的,难怪我无法弄清楚。我一直在看'_com_ptr_t',它没有这个问题! – abelenky

+0

实际上,我完全忘记了CComPtr的这个问题,直到我看到你的问题:) –

+0

我不记得CComPtr是否仍然支持它或者,但它*使用*有一个调试模式来检测'operator& '如果在非空实例上触发则会抛出一个断言。不知道它是否仍然存在。 – WhozCraig

6

这些是ATL :: CComPtr智能指针(这些指针稍微聪明,顺便说一句)。

该对象类型的operator &返回其中的原始接口指针的地址。因此,第一个循环实际上并没有比这样做更好:

IObject* pObj = NULL; 
for (int i(0); i<MAX; i++) 
{ 
    spOtherObj->get_Obj(&pObj); 
} 

每次迭代都不会释放先前迭代的接口。它只是丢失,泄漏,并且底层coclass上的引用计数将被人为地锁定。

通过移动智能指针内循环,你现在让析构函数的智能指针对象清理获取的每个接口的,发射->Release(),下一次迭代之前。扩展后的代码实际上是这样的:

for (int i(0); i<MAX; i++) 
{ 
    IObject* pObj = NULL; 
    spOtherObj->get_Obj(&pObj); 
    if (pObj) pObj->Release(); 
}