c++ - 如何更好地为不可创建的 COM 对象初始化引用计数器?

标签 c++ windows visual-c++ com reference-counting

我有一个 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() 失败的情况下对象删除的实现方式。因为我完全控制了 CCreatorInterfaceImplCObjectToCreateImpl 我可以选择任何一种方式。

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/

相关文章:

c++ - 图像深度和 channel 之间的差异

c# - 在 Windows 7 上使用 .NET 以编程方式创建/销毁网桥

windows - cpp_redis::subscriber -> connect 导致异常:connect() 失败

windows - 尽管我在 app.json 中设置了一个 android 程序包,但仍出现错误 "Your project must have an Android package set in app.json"

c++ - 将函数参数限制为某些枚举值

c++ - 从文件夹 C++ 中获取文件名

c++ - for循环中的数组索引

c++ 为什么我不能将 CDC 和 CBitmap 类型传递给另一个类的参数?

C++ RPC 教程?

c++ - 将名称转换为数字,然后生成输出