我有一个带有返回对象的方法的COM接口:
interface ICreatorInterface {
HRESULT CreateObject( IObjectToCreate** );
};
关键是调用ICreatorInterface::CreateObject()
是检索实现IObjectToCreate
接口的对象的唯一方法。
在C ++中,我可以这样做:
HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
{
//CObjectToCreateImpl constructor sets reference count to 0
CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
if( FAILED(hr) ) {
delete newObject;
}
return hr;
}
或者这样
HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
{
//CObjectToCreateImpl constructor sets reference count to 1
CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
// if QI() failed reference count is still 1 so this will delete the object
newObject->Release();
return hr;
}
区别在于如何初始化引用计数器以及在QueryInterface()
失败的情况下如何实现对象删除。由于我完全控制CCreatorInterfaceImpl
和CObjectToCreateImpl
,我可以选择其中任何一种方式。
IMO第一个变体更清晰 - 所有引用计数的东西都在一段代码中。我监督过什么吗?为什么第二种方法会更好?以上哪个更好,为什么?
答案 0 :(得分:3)
这两种变体都违反了COM的基本原则
否则会导致各种错误。简单地说,因为它阻止人们对对象进行完全合法的操作。就像将它们放入智能指针一样。智能指针将调用AddRef,将计数置于1,稍后释放将计数置于0并使对象自毁。
是的,我意识到QueryInterface的90%的实现都没有这样做。但我也向你保证,那里有一些可以做到的:)
我认为最简单的方法是在创建对象后立即调用AddRef。这允许对象在尽可能早的时刻表现得像普通的COM对象。
我在过去遇到过这个问题,并且我编写了一个很好的小助手方法(假设该对象是在ATL中实现的)。
template <class T>
static
HRESULT CreateWithRef(T** ppObject)
{
CComObject<T> *pObject;
HRESULT hr = CComObject<T>::CreateInstance(&pObject);
if ( SUCCEEDED(hr) )
{
pObject->AddRef();
*ppObject = pObject;
}
return hr;
}
答案 1 :(得分:2)
Raymond Chen在他的博客上写了一篇相关文章: On objects with a reference count of zero
答案 2 :(得分:0)
我总是使用以下代码场景来创建返回的com对象,以避免内存问题。当然这是有效的,因为我的对象在创建时被引用count = 0。对于我而言,这总是比使用delete运算符来处理错误条件更清晰。
HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
{
//CObjectToCreateImpl constructor sets reference count to 0
CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
newObject->AddRef();
HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result);
newObject->Release(); // release my addref, if QI succeeded it AddRef'd, if not the object is destroyed
return hr; // return result from QI
}