Reference Counting Rules

ID: Q104138

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.

1. 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();
       }

2. 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.

Additional reference words: 2.00 3.50 4.00 KBCategory: kbole kbprg KBSubcategory: LeTwoCom

Last Reviewed: May 17, 1995