我有一个 COM 接口(interface),它有一个返回对象的方法:
interface ICreatorInterface {
HRESULT CreateObject( IObjectToCreate** );
};
关键是调用ICreatorInterface::CreateObject()
是检索实现IObjectToCreate
接口(interface)的对象的唯一方法。
在 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 第一个变体更清晰——所有引用计数的东西都在一段代码中。我监督了什么吗?为什么第二种方法会更好?以上哪个更好,为什么?
最佳答案
这两种变体都违反了 COM 的一个非常基本的原则
- 切勿在引用计数为零的 COM 对象上调用除 AddRef 之外的任何方法。
否则会导致各种错误。简单的说是因为它阻止了人们对对象进行完全合法的操作。就像将它们放入智能指针中一样。智能指针会调用 AddRef,将计数置为 1,然后 Release 将计数置为 0 并导致对象自毁。
是的,我知道 90% 的 QueryInterface 实现都没有这样做。但我也向你保证,有一些可以做到 :)
我认为最简单的方法是在创建对象后立即调用 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;
}
关于c++ - 如何更好地为不可创建的 COM 对象初始化引用计数器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2070111/