Topic: STL Proposal: holder and envelope classes


Author: jkauer@opal.tufts.edu (Jonathan Borden)
Date: 1995/07/21
Raw View
Proposal for addition to STL

Holder & Envelope standard template classes

Jonathan A. Borden (c) 1995
JABR Technology Corporation
Component Medical Software

Abstract:
  There exists a class of operations concerning pointers and
other predefined structures which can be performed in a generic fashion.
When using pointers within STL containers it is common to apply a
"holding" operation on the pointer (such as reference counting the
object pointed to) when adding the pointer to the container and
a "releasing" operation when the pointer is removed from the container.

 template <class POINTER_TYPE,class HOLD,class RELEASE> holder

encapsulates these generic operations in a constent format which greatly
eases the use of pointers with STL containers and also eases the
use of pointers and other predefined structures when recovering
from exceptions.

 template <class DERIVED_POINTER_TYPE,class HOLDER_TYPE> envelope

similarly encapsulates using the base holder class on pointers derived
from the base class.
 The code required to represent these operations is very simple and
easy to implement and will be presented.

Introduction:
     The problems in using pointers with STL derive from the semantics of
construction and destruction of pointers. These problems arise in common
situations in dealing with memory management (preventing memory leaks) and
in releasing system resources. Our work with Windows NT multithreading, MFC &
OLE has identified several common operations.

1) critical sections

 A critical section (windows NT CRITICAL_SECTION) is enter'd to hold
the critical section and then leave'd to release the critical section. If
a critical section is entered in a routine, exception cleanup code is
required to release the critical section before the scope is exited i.e.

CRITICAL_SECTION cs;

void example()
{
  try
  {
 ::EnterCriticalSection(&cs);
 ...
  }
  catch(...)
  {
 ::LeaveCriticalSection(&cs);
 throw;
  }
  ::LeaveCriticalSection(&cs);
}

 Another example is when using OLE/COM and IUnknown derived pointers:

void another_example(IUnknown* pUnk,IOleObject* pOleObj)
{
 pUnk->AddRef();
 pOleObj->AddRef();

 ...

 if (error)
 {
  pUnk->Release();
  pOleUnk->Release();
  return;
 }

 ...

 pUnk->Release();
 pOleObj->Release();
 return;

}

 These operations can be generically encapsulated by holder &
envelope objects:

typedef holder<CRITICAL_SECTION*,Enter,Leave> cs_holder;
typedef holder<IUnknown*,AddRef,Release> com_holder;

void example()
{
 cs_holder(&cs);
 throw whatever; // calls ::LeaveCriticalSection in cs_holder destructor

 ole_holder x(pUnk);  // calls pUnk->Release() in destructor

 vector<ole_holder> ole_vector V;
 V.push_back(pUnk);  // encapsulates vector of pointers
 V.push_back(pAnotherUnk);
}

DEFINITIONS:
  Functor class examples:

        class AddRef
 {
  operator()(LPUNKNOWN p){ p->AddRef();};
  operator()(CCmdTarget * p}{ p->ExternalAddRef();}
 };
 class Enter
 {
  operator()(CRITICAL_SECTION* pcs){::EnterCriticalSection(pcs)};
 }

 holder class
 template <class T,class HOLD,class RELEASE> holder
        {
   public:
  typedef T element_type;
  holder(T p,BOOL bHold=TRUE) : _p(p)
   { if (_p && bHold) HOLD(_p); };
  holder() : _p(NULL) {};
  ~holder(){ if (_p) RELEASE(_p)};
  operator T(){ return _p;};
  T operator->(){ return _p;};
  T operator=(T p){ if (_p) RELEASE(_p); _p = p; if (_p)
HOLD(_p);};
  private:
  T _p;
 }
 envelope class
 template <class DERIVED,class HOLDER> envelope : public holder
 {
   public:
  envelope(const DERIVED& d) : holder((holder::element_tyoe)d) {};
  operator DERIVED(){ return
(DERIVED)(holder::element_type)*this;};
 };

 Note: as "inline" classes holder & envelope use the same storage space
as the base pointer and semantically can be used where the base pointer is
desired. The code presented above is very efficient but chokes the Visual C++
compiler & debugger as presented above. We have modified the classes to
work better with the current Visual C++ 2.2 compiler. Feel free to email
me for methods to work around these problems if they arise.

jon borden
jabr technology corporation

jon@synapse.nsur.nemc.org
617-636-5858