为什么我的 COM 智能指针在从方法返回时被删除

Why does my COM Smart Pointer get deleted when returning from method

为什么我的 COM 智能指针在我 return 从 func.我认为它仍在范围内。有没有办法避免这种情况?

这是.TLH文件中的定义

_COM_SMARTPTR_TYPEDEF(IComItem, __uuidof(IComItem));

static IComItemPtr m_pItem;

LPDISPATCH func()
{
    IComItemPtr  pItem = m_pItem;

    pItem = pItem->GetParent();  // Returns parent as IComItemPtr

    return pItem;   // Gets deleted here

}

您的函数的 return 类型是原始 IDispatch* 指针,而不是 IComItemPtr 对象(或至少是 IDispatchPtr 对象)。您看到的问题是由于您错误地将智能指针与原始指针混合使用造成的。

由于您的函数不是 return 智能包装对象,因此必须执行转换以将 pItem 转换为 IDispatch*pItem 在这种情况下可以执行的 The only conversionIComItem*,然后编译器可以将其隐式转换为 IDispatch*(因为 IComItem 派生自 IDispatch, 否则你的代码根本无法编译)。

IOW,您的 return 语句实际上是在执行以下逻辑:

LPDISPATCH func()
{
    IComItemPtr  pItem = m_pItem;

    pItem = pItem->GetParent();  // Returns parent as IComItemPtr

    //return pItem;
    IComItem *pTemp = pItem.operator IComItem*();
    IDispatch *pDisp = (IDispatch*) pTemp;
    return pDisp;

} // <-- pItem is destructed here!

无论如何,当函数退出时,pItem 本身总是会超出范围,如果 pItem 正在引用一个对象,则会减少对象的引用计数。

所以,重要的是你 return 一个 IDispatch* 指向一个有效对象的指针,该对象的引用计数增加了,这样当 pItem 的析构函数减少时该对象就不会被释放它的引用计数。

试试这个:

IComItemPtr func()
{
    return m_pItem->GetParent();  // Returns parent as IComItemPtr
}

或者:

IDispatchPtr func()
{
    return m_pItem->GetParent();  // Returns parent as IComItemPtr converted to IDispatchPtr
}

如果您绝对必须 return 原始 IDispatch* 指针,那么您必须:

  • 退出前手动增加引用计数:

    LPDISPATCH func()
    {
        IComItemPtr pItem = m_pItem->GetParent();  // Returns parent as IComItemPtr
        pItem.AddRef();
        return pItem;
    }
    
  • 手动从包装器中分离指针:

    LPDISPATCH func()
    {
        IComItemPtr pItem = m_pItem->GetParent();  // Returns parent as IComItemPtr
        return pItem.Detach();
    }
    

你的第一个假设是不正确的。

static IComItemPtr m_pItem;

LPDISPATCH func()
{
    IComItemPtr  pItem = m_pItem;

    pItem = pItem->GetParent();

    return pItem;  // not here.

}   // Gets deleted here (this is where scope is closed).

return 会在调用析构函数之前将 pItemIComItemPtr 转换为 LPDISPATCH (IDispatch*)。此转换的结果将放在目标中。

注意:转换如何发生将完全取决于所涉及类型的确切定义。