4

我有一个带有返回对象的方法的 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()失败时如何实现对象删除。因为我完全控制了两者CCreatorInterfaceImplCObjectToCreateImpl所以我可以选择任何一种方式。

IMO 第一个变体更清晰——所有引用计数的东西都在一段代码中。我监督了什么?为什么第二种方法会更好?以上哪个更好,为什么?

4

3 回答 3

3

Both variations violate a very fundamental principle of COM

  • Never call any method, other than AddRef, on a COM object that has a ref count of zero.

To do otherwise leads to all sorts of errors. Simply put because it prevents people from doing completely legal operations on the object. Like putting them into a smart pointer. The smart pointer would call AddRef, put the count to 1, and later Release putting the count to 0 and causing the object to self destruct.

Yes I realize that 90% of the implementations of QueryInterface don't do this. But I also guarantee you that there are some out there that do :)

I think the simplest approach is to call AddRef immediately after creating the object. This allows the object to behave like a normal COM object at the earliest possible moment.

I've run into this problem in the past and I've written a nice little helper method (assuming the object is implemented in 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; 
}
于 2010-01-15T07:56:24.863 回答
2

Raymond Chen在他的博客上写了一篇相关文章: 关于引用计数为零的对象

于 2010-01-15T09:07:57.433 回答
0

我总是使用以下代码场景来创建返回的 com 对象以避免内存问题。当然这是可行的,因为我的对象在创建时引用计数 = 0。这对我来说似乎总是比尝试使用删除运算符处理错误情况更清楚。

 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
 }
于 2010-01-15T14:06:42.890 回答