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