The information in this article applies to:
SUMMARY
In the component object model, an interface's lifetime is controlled
through reference counting. The reference count for an interface is
manipulated through the AddRef() and Release() member functions
inherited from IUnknown. The AddRef() member increments an interface's
reference count, and the Release() method decrements it. Once an
interface's reference count goes to zero, there are no longer any
valid pointers to that interface. If the reference count on all of an
object's interfaces is zero, then the object can be freed because
there are no longer any pointers to the object.
MORE INFORMATION
Reference Counting Rules
The following list is a copy of the reference counting rules (taken
from pages 83 and 84 of the OLE 2.0 specification) that must be
followed. Small code samples have been added in this article to help
clarify the rules.
- Every new copy of an interface pointer must be AddRef()'d, and
every destruction of an interface pointer must be Release()'d
except where subsequent rules explicitly permit otherwise.
a. In-Out parameters to functions: The caller must AddRef() the
actual parameter, because it will be Release()'d by the callee
when the out-value is stored on top of it.
LPOLEOBJECT lpObject;
.
. // Get pointer to IOleObject.
.
LPVIEWOBJECT lpView = lpObject;
lpObject->AddRef()
// GetViewObject is a theoretical function that takes a
// pointer to anything derived from IUnknown, and then
// returns a pointer to IViewObject in the same variable
// passed as the parameter. The AddRef() above is needed so
// that the original pointer to IOleObject is not freed.
GetViewObject(lpView);
b. Fetching a global variable: The local copy of an interface
pointer fetched from an existing copy of the pointer in a global
variable must be independently reference counted because called
functions might destroy the copy in the global while the local
copy is still alive.
void function()
{
// Get a pointer to IOleObject from a global variable.
LPOLEOBJECT lpOleObject = glpObject;
// This AddRef() is needed so that the interface
// pointed to by the global variable, glpObject,
// does not get released by a different part of
// the applications code.
lpOleObject->AddRef();
.
. // use lpOleObject;
.
lpOleObject->Release();
}
c. New pointers synthesized out of "thin air": A function that
synthesizes an interface pointer using special internal
knowledge rather than obtaining it from some other source must
do an initial AddRef() on the newly synthesized pointer.
Important examples of such routines include instance creation
routines, implementations of IUnknown::QueryInterface, and so
forth.
STDMETHDOIMP IUnknown::QueryInteface( REFIID iidInterface,
LPVOID FAR *ppvObj)
{
*ppvObj = NULL;
SCODE sc = E_NOINTERFACE;
if (iidInterface == IUnknown)
{
*ppvObj = this;
// This AddRef() is needed because a new pointer
// was just created.
AddRef();
sc = S_OK;
}
return ResultFromScode(sc);
}
d. Returning a copy of an internally stored pointer: Once the
pointer has been returned, the callee has no idea how its
lifetime relates to that of the internally stored copy of the
pointer. Thus, the callee must AddRef() the pointer copy before
returning to it.
// m_lpOleObject is a private member variable of a C++ class.
// GetOleObject is a member function to return access to this
// pointer.
void GetOleObject (LPVOID FAR *ppObject)
{
*ppObject = m_lpOleObject;
// This AddRef() is needed due to this rule.
m_lpOleObject->AddRef();
}
- Special knowledge on the part of a piece of code about the
relationships of the beginnings and endings of the lifetimes of two
or more copies of an interface pointer can allow AddRef()/Release()
pairs to be omitted.
a. In-parameters to functions: The copy of an interface pointer
that is passed as an actual parameter to a function has a
lifetime that is nested in that of the pointer used to
initialize the value. Therefore, the actual parameter need not
be separately reference counted.
void function (LPOLEOBJECT lpOleObject)
{
// Can use lpOleObject in this function
// without doing AddRef() and Release().
}
b. Out-parameters from functions, including return values: To set
the out parameter, the function itself by Rule 1 must have a
stable copy of the interface pointer. On exit, the
responsibility for releasing the pointer is transferred from the
callee to the caller. Thus, the out parameter need not be
referenced counted.
LPVIEWOBJECT lpView;
HERROR hErr = lpOleObject->QueryInterface(IID_IViewObject,
(LPVOID FAR *)lpView);
if (hErr = NOERROR)
{
// The QueryInterface succeeded. lpView does not have
// to be AddRef()'d because it has already been done
// by the QueryInterface method.
}
c. Local variables: A function implementation clearly has
omniscient knowledge of the lifetimes of each of the pointer
variables allocated on the stack frame. It can therefore use
this knowledge to omit redundant AddRef()/Release() pairs.
void function()
{
LPOLEOBJECT lpTempObject;
.
.
.
lpTempObject = lpObject;
.
. // lpTempObject can be used
. // without reference counting as long as
. // it is known that the lifetime of lpObject
. // outside of this function call.
.
}
d. Backpointers. Some data structures are of the nature of
containing two components, A and B, each with a pointer to the
other. If the lifetime of one component (A) is known to contain
the lifetime of the other (B), then the pointer from the second
component back to the first (from B to A) need not be reference
counted. Often, avoiding the cycle that would otherwise be
created is important in maintaining the appropriate freeing
behavior.
|