COM object created by CComObject::CreateInstance not destroyed when pointer goes out of scope
Asked Answered
E

1

8

Using smart pointer CComObject I create a COM object by calling its static method CreateInstance. But when I leave my program, at least in VS13, that object remains running. Here is my code:

CComObject< CMyAtlObject > * myAtlCOMObject = NULL;
HRESULT hr = CComObject< CMyAtlObject >::CreateInstance(&myAtlCOMObject);
ASSERT(SUCCEEDED(hr));

I expected the ~CComObject() method to be called when going out of scope which does not happen.

I tried putting the code above in curly braces to force the newly created object to go out scope. I tried calling FinalRelease on myAtlCOMObject and succeeded in manually calling Release on myAtlCOMObject, but the program still didn't stop running in VS13.

What am I missing?

Emersed answered 1/9, 2014 at 14:38 Comment(0)
N
10

Here is the code with inline comments:

{
  CComObject<CMyAtlObject>* myAtlCOMObject = NULL;
  HRESULT hr = CComObject< CMyAtlObject >::CreateInstance(&myAtlCOMObject);
  ASSERT(SUCCEEDED(hr));
  // NOTE: Created new object with reference count of ZERO
  {
    const CComQIPtr<IMyAtlObject> pMyAtlObject = myAtlCOMObject;
    // NOTE: Reference count increased to ONE
  }
  // NOTE: ~CComQIPtr went out of scope and called IUnknown::Release 
  //       decrementing counter to ZERO; decrement to zero causes destruction
}
// NOTE: There is no ~CComObject call here on myAtlCOMObject going out of scope
//       since myAtlCOMObject is a raw pointer

What am I missing?

You are missing the following:

  • CreateInstance creates a new object and gets you raw pointer which is not going to self-destroy on leaving scope
  • CreateInstance creates an object in "unstable" state with refcount of zero, it's self-desrtuction on reference management starts after something increments refcount AT LEAST ONCE and then decrements it to zero; CComQIPtr above is an example of this

MSDN on CreateInstance:

The object returned has a reference count of zero, so call AddRef immediately, then use Release to free the reference on the object pointer when you're done.

What do you use instead of CComObject::CreateInstance?

I have a helper template class CObjectPtr which acts in the way similar to well known CComPtr and wraps/manages native C++ class.

My code would be:

CObjectPtr<CFoo> pFoo;
pFoo.Construct(); // Instantiates automatically adding reference
CFoo* pRawFoo = pFoo; // Acts as a pointer
CComPtr<IFoo> pFooInterface = pFoo; // Good for exposing inmepleted interafaces
CObjectPtr<CFoo> pAnotherFoo = pFoo; // Same instance proper reference counting
// ~CObjectPtr releases reference, destroys the object on last release

Another simple wrapper is also provided in this answer: How to better initialize a reference counter for a non-creatable COM object?.

Nesselrode answered 1/9, 2014 at 14:53 Comment(5)
Got it. I can now exit my MFC program and the memory leak dumps work again because the COM objects have been properly released.Emersed
No! If you use CComQIPtr with an interface type which is for whatever reason unsupported by the object you get the object leaked. It should be CComPtr here instead.Candlewood
This is correct, my code snippet was somewhat simplifying things. Both CComPtr, CComQIPtr do fine if interface is implemented/available. Otherwise CComPtr would rather cause compiler error, and CComQIPtr would rather fail on runtime instead. I personally never use CComObject::CreateInstance directly on real code.Nesselrode
What do you use instead of CComObject::CreateInstance? CoCreateInstance?Emersed
@Emersed presumably CoCreateInstance would end up in this code. You are instantiating a C++ class which implements a COM object so I am assuming this code appears in a class factory that you are writing yourself.Elianaelianora

© 2022 - 2024 — McMap. All rights reserved.