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

时间:2017-12-07 23:41:20

标签: c++ com

为什么我的COM智能指针在从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

}

2 个答案:

答案 0 :(得分:3)

您的函数的返回类型是原始IDispatch*指针,而不是IComItemPtr对象(或至少是IDispatchPtr个对象)。您看到的问题是由于您错误地将智能指针与原始指针混合在一起。

由于您的函数未返回智能包装器对象,因此必须执行转换才能将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引用对象,则递减对象的引用计数。

所以,重要的是你返回一个IDispatch*指向一个有效对象的指针,该对象的refcount递增,这样当pItem的析构函数递减其引用计数时,对象不会被释放。

请改为尝试:

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

或者:

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

如果绝对必须返回原始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();
    }
    

答案 1 :(得分:0)

您首先假设不正确。

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).

在调用析构函数之前,返回会将pItemIComItemPtr转换为LPDISPATCHIDispatch*)。此转换的结果将放在目的地。

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