CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    Sep 2002
    Posts
    115

    CComPtr thoughts, please comment!

    Hi,

    I've done some work with CComPtr and some thoughts, regarding when they are pointless to use and when AddRef is NOT called, troubles me. Maybe I've got it all wrong, maybe I've missed something really basic, so please share your wisdom with me!


    "Pointless" or not?
    =============

    As far as I understand, the main idea of using CComPtr is to get an automatic reference counter. This works great in many situations, e.g. when you use it's constructor / assign operator to assign it an interface pointer or call its CoCreateInstance() method.

    But, consider this:

    ITest* pITest = NULL;
    GetITest(&pITest);

    GetITest() will as is common in such functions (that receives a pointer to an interface pointer), provide an interface pointer to an ITest object and call AddRef() on the object before returning. For instance, as IConnectionPointContainer::FindConnectionPoint() does.

    So, when I'm done using pITest, I have to call pITest->Release().

    Now, if I would use a CComPtr instead, it would look like something like this:

    CComPtr<ITest> pITest;
    GetITest(&pITest);

    The "problem" is that when I'm done using pITest I cannot depend on the destructor in CComPtr to call Release(). I can't do this because CComPtr doesn't have a clue that AddRef was called by GetITest(). Instead I have to manually call pITest.Release() before it goes out of scope. So, for this situation I find it not only pointless but even dumb to use a CComPtr instead of a simple interface pointer, as the CComPtr gives you a false sense of safety.

    It would have been very neat though if it would be possible to inform the CComPtr class that AddRef has already been called, so it would call Release() in the destructor. Calling AddRef on the CComPtr is of course not a solution.
    But is there a trick for this!?

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: CComPtr thoughts, please comment!

    Are you sure release isn't getting called? Have you set a break point on the destructor to verify?

    Looking at the 2005 ATL code, CComPtr is derived from CComPtrBase and the destructor is defined as:

    Code:
     ~CComPtrBase() throw() 
    {
    if (p)
    	p->Release();
    }
    I would expect the older versions of the code to be similar, but you can set a bp and verify your self.

    Keep in mind that the destructor won't get called until the object goes out of scope. So you may wish to scope the pointer to control when the release occurs:

    Code:
     
    { // Scoping block
    CComPtr<ITest> pITest;
    GetITest(&pITest);
     
    // Use the pointer
     
    } // Pointer released here
    Arjay

  3. #3
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: CComPtr thoughts, please comment!

    Quote Originally Posted by ackabacka
    It would have been very neat though if it would be possible to inform the CComPtr class that AddRef has already been called, so it would call Release() in the destructor. Calling AddRef on the CComPtr is of course not a solution.
    But is there a trick for this!?
    As Arjay has already explained - CComPtr does the AddRef and Release for you at the right places. The best way to verify how stuff works with a smart pointer as this one is to place a breakpoint inside it's code (which is visible - it being a template).

    There are some more benefits too of using COM Smart Pointers (just incase the one before wasn't great enough)...

    Smart pointers like CComQIPtr perform automatic QueryInterface for you. That saves a lot of code and effort too. i.e. You can do this -
    Code:
    CComQIPtr <IAnInterface> spExistingInterface;
    spExistingInterface.CoCreateInstance (L"Library.Class");
    
    // Automatic QueryInterface
    CComQIPtr <ISomeInterfaceBeingQueriedFor> spSomeIntPtr (spExistingInterface);
    
    if (spSomeIntPtr)
    	// Do something with a valid pointer
    	spSomeIntPtr->SomeMethod ();
    ...And if you didn't notice - using smart pointers, I could create an instance of a COM object with 1 parameter rather than 5 required for CoCreateInstance (which was invoked internally by the Smart Pointer Class for the programmer).
    Last edited by Siddhartha; February 14th, 2006 at 01:34 PM. Reason: Spelling...

  4. #4
    Join Date
    Sep 2002
    Posts
    115

    Thumbs up Re: CComPtr thoughts, please comment!

    Quote Originally Posted by Arjay
    Are you sure release isn't getting called? Have you set a break point on the destructor to verify?
    ... ehhh me feeling really stupid! But on the other hand that was the whole point of this thread, i.e. I felt trapped in my thinking and need another persons opinion.


    Quote Originally Posted by Arjay
    Looking at the 2005 ATL code, CComPtr is derived from CComPtrBase and the destructor is defined as:

    Code:
     ~CComPtrBase() throw() 
    {
    if (p)
    	p->Release();
    }
    I would expect the older versions of the code to be similar, but you can set a bp and verify your self.
    Sure, that's exactly what it looks like in VC6 as well.

    I had this idea that CComPtr had its own reference counting system. So, if AddRef was ever called on the object someone else but CComPtr, then CComPtr's destructor wouldn't know. I also thought that if I would CComPtr's AddRef multiple times, then CComPtr's destructor would release them all. But, the source clearly code shows differently!
    I guess one reason for why I got this crazy idea and never checked the sources on that specific point (I have examined the CComPtr sources alot but never the destructor!!!) was that CComPtr prohibits calling the underlaying objects ->AddRef() and ->Release().

    Thanks alot for taking the time to read my thread and to show me the obvious that I due to some reason had locked out from my brain.

  5. #5
    Join Date
    Sep 2002
    Posts
    115

    Re: CComPtr thoughts, please comment!

    Quote Originally Posted by Siddhartha
    As Arjay has already explained - CComPtr does the AddRef and Release for you at the right places. The best way to verify how stuff works with a smart pointer as this one is to place a breakpoint inside it's code (which is visible - it being a template).

    There are some more benefits too of using COM Smart Pointers (just incase the one before wasn't great enough)...

    Smart pointers like CComQIPtr perform automatic QueryInterface for you. That saves a lot of code and effort too. i.e. You can do this -
    Code:
    CComQIPtr <IAnInterface> spExistingInterface;
    spExistingInterface.CoCreateInstance (L"Library.Class");
    
    // Automatic QueryInterface
    CComQIPtr <ISomeInterfaceBeingQueriedFor> spSomeIntPtr (spExistingInterface);
    
    if (spSomeIntPtr)
    	// Do something with a valid pointer
    	spSomeIntPtr->SomeMethod ();
    ...And if you didn't notice - using smart pointers, I could create an instance of a COM object with 1 parameter rather than 5 required for CoCreateInstance (which was invoked internally by the Smart Pointer Class for the programmer).
    Hi Siddharta,

    Well this time it was old news to me (but on the other hand perhaps it may be useful for someone else reading this!).
    Even if I made a mistake regarding the destructor, I'm well aware about the usefullness of the constructors of both CComPtr and CComQIPtr and use them alot. Thanks anyway!

  6. #6
    Join Date
    Oct 2007
    Posts
    9

    Re: CComPtr thoughts, please comment!

    Sorry for posting in such an old thread but it came right at top of google and i am feeling lucky

    I have 2 doubts regarding CComPtr

    1. What if I explicitly call release on CComPtr

    Code:
    void foo()
    {
    CComQIPtr <IAnInterface> spExistingInterface;
    spExistingInterface.CoCreateInstance (L"Library.Class");
    
    // Automatic QueryInterface
    CComQIPtr <ISomeInterfaceBeingQueriedFor> spSomeIntPtr (spExistingInterface);
    
    if (spSomeIntPtr)
    {
    	// Do something with a valid pointer
    	spSomeIntPtr->SomeMethod ();
            spSomeIntPtr.Release(); //explicitly calling. 
    }
    } //here release will be called again as com ptr goes out of scope. any problem or crash possible here?? 
    2. Do I need to release com ptr passed as function argument.
    Consider this

    Code:
    void foo1()
    {
    CComQIPtr <IAnInterface> spExistingInterface;
    spExistingInterface.CoCreateInstance (L"Library.Class");
    
    foo2(spExistingInterface);
    }
    
    void foo2( IAnInterface* pInterface )  //should I use CComPtr<IAnInterface> here?? 
    {
     pInterface->AbraCaDabra();
     pInterface->release(); //is this required???
    }

  7. #7
    Join Date
    Sep 2002
    Posts
    115

    Re: CComPtr thoughts, please comment!

    Quote Originally Posted by vivek.m View Post
    Sorry for posting in such an old thread but it came right at top of google and i am feeling lucky

    I have 2 doubts regarding CComPtr

    1. What if I explicitly call release on CComPtr

    Code:
    void foo()
    {
    CComQIPtr <IAnInterface> spExistingInterface;
    spExistingInterface.CoCreateInstance (L"Library.Class");
    
    // Automatic QueryInterface
    CComQIPtr <ISomeInterfaceBeingQueriedFor> spSomeIntPtr (spExistingInterface);
    
    if (spSomeIntPtr)
    {
    	// Do something with a valid pointer
    	spSomeIntPtr->SomeMethod ();
            spSomeIntPtr.Release(); //explicitly calling. 
    }
    } //here release will be called again as com ptr goes out of scope. any problem or crash possible here?? 
    2. Do I need to release com ptr passed as function argument.
    Consider this

    Code:
    void foo1()
    {
    CComQIPtr <IAnInterface> spExistingInterface;
    spExistingInterface.CoCreateInstance (L"Library.Class");
    
    foo2(spExistingInterface);
    }
    
    void foo2( IAnInterface* pInterface )  //should I use CComPtr<IAnInterface> here?? 
    {
     pInterface->AbraCaDabra();
     pInterface->release(); //is this required???
    }
    As I created this thread, I feel I should give it ago and try to help someone else out. ;-)

    CComQIPtr inherits from CComPtrBase.

    As far as I can tell, calling Release will not only call release on the interface, but also set its internal pointer variable (p) to NULL.

    "The interface is released, and CComPtrBase: is set to NULL."

    So, (just like Arjey pointed out a few years ago) as the destructor first checks if (p) before it runs release, it should be safe to "manually" call Release.

    ~CComPtrBase() throw()
    {
    if (p)
    p->Release();
    }

  8. #8
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: CComPtr thoughts, please comment!

    When using CComPtr or CComQIPtr, one would normally not call Release() at all. That's what smart pointers are for -- they do the reference counting for you. i.e. When the smart pointer object goes out of scope, its destructor would be invoked which would call Release() on the interface pointer for you.

    However, if you really do want to invoke Release() yourself, then version 1 would be fine i.e. sp.Release() that calls the Release() member funtion of the smart pointer class, thereby giving it an opportunity to clear up it's internal raw pointer state after invoking Release() on the same.

  9. #9
    Join Date
    Oct 2007
    Posts
    9

    Re: CComPtr thoughts, please comment!

    Thanks ackabacka and siddhartha for reply.

    Actually, why I asked first doubt is because of some member variable COM pointer and there's a function like CleanPointers() that releases all pointers. It is called by other functions and also inside the destructor. My doubt was that if I already release the COM pointer, then do I need to put some check in d'tor not to call release again. But as I gathered from your post, it is not required.

    What about my second doubt - regarding passing pointers as function arguments?
    Do I need to release?

  10. #10
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: CComPtr thoughts, please comment!

    Quote Originally Posted by vivek.m View Post
    What about my second doubt - regarding passing pointers as function arguments?
    Do I need to release?
    No, you dont need to release as the destructor always takes care of it.

    (That's why the pointers are called smart -- as they also do the AddRef for you, when you pass them by value and Release when they go out of scope. An alternative would be to pass by reference, which makes sense too -- eitherways, no need to call Release.)

  11. #11
    Join Date
    Sep 2002
    Posts
    115

    Re: CComPtr thoughts, please comment!

    While we are at it ;-), there is another com ptr related thing that puzzles me and I'm pretty sure it puzzles several others too.

    Sometimes (depending on project) I import the tlb and then work with the auto generated smart pointers (based on t_com_ptr).

    In this case it's _ApplicationPtr, but I'm sure the answer is the same no matter the type.

    Normally I simply type
    Code:
      _ApplicationPtr pApp;
      pApp.CreateInstance (__uuidof(Application));
    and after that the object is created and it's functions and properties are accessable via the pApp.

    But, sometimes I would like call a function that creates the instance and "returns" it. The problem is that I don't know how to send a pointer to my pApp... it's not as simple to write &pApp. I've tried to retreive the raw interface pointer and send that and similar thing, but I can't seem to get it just right.

    Anyone?

  12. #12
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: CComPtr thoughts, please comment!

    You can create a function like:

    Code:
    HRESULT CreateCOMObject (SmartPointerType & sp)
    {
        return sp.CreateInstance (...);
    }
    
    void DoSomething ()
    {
        SmartPointerType spObject;
    
        if (SUCCEEDED (CreateCOMObject (spObject)))
            spObject->Function();
    }
    When using Smart Pointers, one should avoid using the raw interface pointer at all costs. That would defeat the purpose of using the smart pointer.
    Last edited by Siddhartha; September 15th, 2009 at 02:59 AM.

  13. #13
    Join Date
    Sep 2002
    Posts
    115

    Red face Re: CComPtr thoughts, please comment!

    Quote Originally Posted by Siddhartha View Post
    You can create a function like:

    Code:
    HRESULT CreateCOMObject (SmartPointerType & sp)
    {
        return sp.CreateInstance (...);
    }
    
    void DoSomething ()
    {
        SmartPointerType spObject;
    
        if (SUCCEEDED (CreateCOMObject (spObject)))
            spObject->Function();
    }
    When using Smart Pointers, one should avoid using the raw interface pointer at all costs. That would defeat the purpose of using the smart pointer.

    Excellent!
    So simply sending it as reference was the solution. Me feeling stupid!
    I try to be a good c++ programmer and avoid sending as reference...

    Anyway, thanks Siddhartha for the very fast reply and a perfectly working solution (even though I expected something more advanced hahaha).

  14. #14
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: CComPtr thoughts, please comment!

    You are welcome...

  15. #15
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: CComPtr thoughts, please comment!

    Quote Originally Posted by ackabacka
    even though I expected something more advanced hahah
    Yes, there is another way too...

    Code:
    HRESULT CreateCOMObject (Interface ** p)
    {
        SmartPointerType <Interface> sp;
        HRESULT hr = sp.CreateInstance (...);
    
        if (SUCCEEDED (hr))
            return sp.CopyTo (p);
        else
            return hr;
    }
    
    void DoSomething ()
    {
        SmartPointerType <Interface> spObject;
    
        if (SUCCEEDED (CreateCOMObject (&spObject)))
            spObject->Function();
    }
    I am using the CopyTo function as provided by CComPtr and CComQIPtr.

    In this case, the CopyTo function seems to be an unnecessary complication as compared to the previous one. Yet, this method is useful (in fact necessary) when the interface pointer needs to be transacted across class boundaries i.e. via methods declared in an IDL where you cannot transact Smart Pointer objects and need to transact raw interface pointers.
    Last edited by Siddhartha; September 15th, 2009 at 03:25 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured