List Info

Thread: Checkin: Add an ability for a smart pointer to adopt a COM pointer




Checkin: Add an ability for a smart pointer to adopt a COM pointer
user name
2006-08-03 17:58:16
Synopsis
========
Add an ability for a smart pointer to adopt a COM pointer

Branches: head
Reviewer: seb, jeffl


Description
===========
Let me begin with a motivating example. Consider the
old-style (non-smart
pointer) code:

// Example 1
SomeClass::someFunc(BasePacket* pPacket)
{
    IHXBuffer *pBuf;
    pBuf = pPacket->GetBuffer(); // GetBuffer does an
AddRef() before returning
    // Do something with pBuf;
    HX_RELEASE(pBuf);
}

Remembering to HX_RELEASE(pBuf) can be annoying, and if one
adds
early exit cases, it can be easily overlooked. So we want to
use smart
pointers. Alas, our first attempt will fail:

// Example 2
SomeClass::someFunc(BasePacket* pPacket)
{
    SPIHXBuffer spBuf;
    spBuf = pPacket->GetBuffer();
    // Do something with spBuf;
}

Why does this leak? Because both pPacket->GetBuffer() and
the
SPIHXBuffer constructor do an AddRef(), but the destructor
only
does one Release().

So how can we fix this? The first two ways involve no
changes to HXCOMPtr<>:

// Example 3
SomeClass::someFunc(BasePacket* pPacket)
{
    IHXBuffer *pBuf;
    pBuf = pPacket->GetBuffer(); // GetBuffer does an
AddRef() before returning
    SPIHXBuffer spBuf = pBuf;
    HX_RELEASE(pBuf);
    // Do something with spBuf;
}

// Example 4
SomeClass::someFunc(BasePacket* pPacket)
{
    SPIHXBuffer spBuf;
    *(spBuf.AsInOutParam()) = pPacket->GetBuffer();
    // Do something with spBuf;
}

That is certainly legal, but ... ugh! In example 3, we wind
up doing
an extra and unnecessary AddRef()/Release() pair, and have
all the
pointer management headaches that smart pointers were to
eliminate;
and in example 4, we have to contort our code to access the
raw COM
pointer inside our smart pointer.

Our other choices involve modifying HXCOMPtr<>. One
possibility would
be to add another constructor, something like this:

// Example 5
SomeClass::someFunc(BasePacket* pPacket)
{
    SPIHXBuffer spBuf(pPacket->GetBuffer(), FALSE);
    // Do something with spBuf;
}

In this case, the constructor with signature
HXCOMPtr<T>::HXCOMPtr(T*,
HXBOOL) simply copies the T* into m_p and doesn't AddRef()
it. As an
aside, the solution could be further refined to add a
default HXBOOL
parameter to the HXCOMPtr<T>::HXCOMPtr(T*) constructor
(like so:
HXCOMPtr<T>::HXCOMPtr(T*, HXBOOL bAddRef = TRUE)), and
use the value of
the HXBOOL to decide whether to AddRef(), but I don't that
that is the
right way to go, as that limits us to making the function
call only at
construction time.

Another possibility would be to add a new method to
HXCOMPtr<> to
allow a smart pointer to "adopt" a dumb COM
pointer that has already
been AddRef()ed. So the example would look like:

// Example 6
SomeClass::someFunc(BasePacket* pPacket)
{
    SPIHXBuffer spBuf;
    spBuf.Adopt(pPacket->GetBuffer());
    // Do something with spBuf;
}

However, after much discussion, the best option is to add a
global
free template function as follows:

// Example 7
template <typename SmartPointer, typename InterfaceT >
inline
void
HXAdoptInterfacePointer( SmartPointer& sp, InterfaceT*
pI )
{
   *(sp.AsInOutParam()) = pI;
}

This is clean and simple, and has the virtue of not breaking
existing
code. Of course, new interfaces should not return such a
pointer, but
this will be quite helpful in dealing with the legacy
interfaces that
currently do this.


Files Affected
==============

common/include/hxcomptr.h


Testing Performed
=================
Verified that leaks (caused by code like example 2) were no
longer happening.
Forced macro-based smart pointers, and verified no leaks
there, either.

Platforms Tested: linux-rhel4-i686
Build verified: linux-rhel4-i686, sunos-5.10-sparc-server,
win32-i386-vc7


QA Hints
===============

Nothing special.

-- 
Timothy Knox <mailto:tknoxreal.com>
"Pain heals. Chicks dig scars. Glory ... lasts
forever."
    -- Keanu Reeves, _The Replacements_

_______________________________________________
Common-dev mailing list
Common-devhelixcommunity.org
http://lists.helixcommunity.org/mailman/listinfo/comm
on-dev
[1]

about | contact  Other archives ( Real Estate discussion Medical topics )