Reference Counting Rules


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.

    1. 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;


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

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

      . // use lpOleObject;
    3. 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;

      if (iidInterface == IUnknown)
      *ppvObj = this;

      // This AddRef() is needed because a new pointer
      // was just created.

      sc = S_OK;

      return ResultFromScode(sc);
    4. 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.

  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.

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

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

Article ID: 104138 - Last Review: Aug 26, 2008 - Revision: 1