简体   繁体   English

这个智能指针使用有什么问题?

[英]What is wrong with this Smart Pointer Use?

I recently saw a PowerPoint on Smart Pointers and their pitfalls, which had this slide (with virtually no commentary or explanation: 我最近看到一个关于智能指针的PowerPoint和他们的陷阱,有这个幻灯片(几乎没有评论或解释:

In context: specifically the _com_ptr_t , Smart Pointer for COM-interfaces that handles AddRef/Release, as created by a _COM_SMARTPTR_TYPEDEF macro.* 在上下文中:特别是_com_ptr_t ,用于处理AddRef / Release的COM接口的智能指针,由_COM_SMARTPTR_TYPEDEF宏创建。*


Wrong: 错误:

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

The next slide claims that it is okay if you put the spObj within the scope of the loop: 下一张幻灯片声称如果将spObj放在循环范围内就可以了:


Right: 对:

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

I've studied this, and still cannot figure out what they're talking about. 我研究了这个,但仍然无法弄清楚他们在谈论什么。
What is the problem with the first one that is solved by the second one?? 第一个解决的问题是第二个解决的问题是什么?


I'm guessing that, in fuller context, the right/wrong code would look like: 我猜测,在更全面的上下文中,正确/错误的代码看起来像:
although I could be wrong in my assumptions 虽然我的假设可能是错的

 _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); } } 

This most likely refers to ATL::CComPtr and not _com_ptr_t . 这很可能是指ATL::CComPtr而不是_com_ptr_t

The problem is that CComPtr::operator& returns the address of the wrapped pointer but doesn't release it, therefore leaking the objects if it is declared out of the loop, assuming that the wrapped interface is not NULL. 问题是CComPtr::operator&返回包装指针的地址但不释放它,因此假设被包装的接口不是NULL,如果它被声明出循环,则泄漏对象。

The implementation acknowledges this fact, this is copied straight from ATL headers, including comments: 实现确认了这一事实,这是直接从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 fixes this problem, and is more convenient to use in general, so it should be preferred were applicable. _com_ptr_t修复了这个问题,并且一般使用起来更方便,因此应该首选适用。

These are ATL::CComPtr smart pointers (which are marginally smart, btw). 这些是ATL :: CComPtr智能指针(它们非常聪明,顺便说一句)。

The operator & for that object type returns the address of the raw interface pointer within. operator &该对象类型返回其中的原始接口指针的地址。 Therefore the first loop is literally no better than doing this: 因此,第一个循环实际上并不比这样做更好:

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

With each iteration, the prior iteration's interface is never released. 每次迭代,都不会释放先前迭代的接口。 It is simply lost, leaked and the reference count on the underlying coclass will be artificially latched up. 它只是丢失,泄露,底层coclass的引用计数将被人为地锁定。

By moving the smart pointer to the inside of the loop, you're now allowing the destructor of the smart-pointer object to clean up each interface acquired, firing ->Release() , before the next iteration. 通过将智能指针移动到循环内部 ,您现在允许智能指针对象的析构函数在下一次迭代之前清理获取的每个接口,kick ->Release() That code, expanded, is effectively this: 扩展的代码实际上是这样的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM