【问题标题】:What is wrong with this Smart Pointer Use?这个智能指针使用有什么问题?
【发布时间】:2013-11-15 21:42:44
【问题描述】:

我最近看到了一个关于智能指针及其陷阱的 PowerPoint,其中有这张幻灯片(几乎没有评论或解释:

在上下文中:特别是 _com_ptr_t,用于处理 AddRef/Release 的 COM 接口的智能指针,由 _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);
}

我研究过这个,但仍然无法弄清楚他们在说什么。
第一个被第二个解决的问题是什么?? p>


我猜想,在更全面的情况下,正确/错误的代码看起来像:
虽然我的假设可能是错误的
_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);
    }
}

【问题讨论】:

  • 没有关于 get_Obj 正在做什么的上下文也无济于事。
  • 指针总是很聪明;)
  • 这里的上下文都是关于_com_ptr_t 指向 COM 对象的智能指针。

标签: c++ com smart-pointers


【解决方案1】:

这很可能是指ATL::CComPtr 而不是_com_ptr_t

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

实现承认这一事实,这是直接从 ATL 标头复制的,包括 cmets:

//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解决了这个问题,一般使用起来更方便,所以应该优先适用。

【讨论】:

  • 很好的答案。如果你是对的,难怪我想不通。我一直在看_com_ptr_t,没有这个问题!
  • 实际上,在看到您的问题之前,我完全忘记了 CComPtr 的这个问题 :)
  • 我不记得 CComPtr 是否仍然支持它或支持它,但它使用有一个调试模式来检测operator &amp; 的调用,如果在非空实例上触发。不知道还有没有。
  • 是的,它仍然有检查,我只是在源代码中查找了它:)
【解决方案2】:

这些是 ATL::CComPtr 智能指针(有点智能,顺便说一句)。

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

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

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

通过将智能指针移动到循环的 inside,您现在允许智能指针对象的 析构函数 清理获取的每个接口,触发-&gt;Release(),在下一次迭代之前。扩展后的代码实际上是这样的:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多