为什么我的 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 conversion 是 IComItem*
,然后编译器可以将其隐式转换为 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 会在调用析构函数之前将 pItem
从 IComItemPtr
转换为 LPDISPATCH
(IDispatch*
)。此转换的结果将放在目标中。
注意:转换如何发生将完全取决于所涉及类型的确切定义。
为什么我的 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 conversion 是 IComItem*
,然后编译器可以将其隐式转换为 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 会在调用析构函数之前将 pItem
从 IComItemPtr
转换为 LPDISPATCH
(IDispatch*
)。此转换的结果将放在目标中。
注意:转换如何发生将完全取决于所涉及类型的确切定义。