代码之家  ›  专栏  ›  技术社区  ›  sharptooth

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

  •  4
  • sharptooth  · 技术社区  · 15 年前

    我有一个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的第一个变体更清晰-所有引用计数的东西都在一段代码中。我监督过什么吗?为什么第二种方法会更好?以上哪一项更好?为什么?

    3 回复  |  直到 15 年前
        1
  •  3
  •   JaredPar    15 年前

    这两种变体都违反了COM的基本原则

    否则会导致各种各样的错误。简单地说是因为它阻止人们对物体进行完全合法的操作。就像把它们放进智能指针。智能指针将调用AddRef,将计数设为1,然后释放,将计数设为0并导致对象自毁。

    是的,我知道QueryInterface 90%的实现都不这样做。但我也向你保证,有一些人是这样做的:)

    我认为最简单的方法是在创建对象之后立即调用AddRef。这允许对象在尽可能早的时候表现得像一个普通的COM对象。

    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; 
    }
    
        3
  •  0
  •   Ruddy    15 年前

    我总是使用下面的代码场景来创建返回的com对象,以避免内存问题。当然,这是有效的,因为我的对象在创建时引用计数为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
     }
    
    推荐文章