What is the best way to initialize a reference counter for a non-created COM object?

I have a COM interface with a method that returns an object:

interface ICreatorInterface { HRESULT CreateObject( IObjectToCreate** ); }; 

The key is that calling ICreatorInterface::CreateObject() is the only way to get an object that implements the IObjectToCreate interface.

In C ++, I could do it like this:

  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; } 

or in this way

  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; } 

The difference is how the reference counter is initialized and how the object is deleted if QueryInterface() fails. Since I have full control over both CCreatorInterfaceImpl and CObjectToCreateImpl , I can go either way.

IMO the first option is clearer - all elements of reference counting are in one piece of code. Am I in control of something? Why could the second approach be better? Which of the above and why?

+4
source share
3 answers

Both options violate the very fundamental principle of COM

  • Never call any method other than AddRef in a COM object with a null value of ref.

Otherwise, it leads to all kinds of errors. Simply put, because it prevents people from completely legal operations on the object. How to put them in a smart pointer. A smart pointer will call AddRef, put the counter at 1 and later. Set the count value to 0 and force the object to destroy on its own.

Yes, I understand that 90% of QueryInterface implementations do not. But I also guarantee you that there are some of them :)

I think the easiest approach is to call AddRef immediately after creating the object. This allows the object to behave like a regular COM object as soon as possible.

I ran into this problem in the past and I wrote 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; } 
+3
source

Raymond Chen wrote a related article on his blog: On sites with zero links

+2
source

I always use the following code script to create returned com objects to avoid memory problems. Of course, this works because my objects reference counted = 0 when created. This always seems clearer to me than trying to handle the error condition with the delete operator.

  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 } 
0
source

Source: https://habr.com/ru/post/1201571/


All Articles