A long time ago, STL had auto_ptr<Type> class that automatically deleted a dynamically allocated C++ object when control leaves a block. Personally, I believe that auto_ptr<Type> was typically used in simple scenarios as a local variable or a class member but theoretically it is even possible to declare a vector of auto_ptr<Type> because auto_ptr<Type> stores an ownership indicator and its copy constructor transfers the ownership from the instance being copied, so vector::push_back(…) and vector::resize(…) functions works correctly.
About 10 years ago when I worked on some C++ projects I written a simple template class TOwner<A> that is a generalization of auto_ptr<Type>. TOwner<A> owns an abstract resource described by an adapter of type A. It stores a handle of type A::Handle and releases the ownership of the resource designated by the handle by calling A::Destroy(Handle h) function. Approximately at the same time some other guy Cristian Vlasceanu did the same work, see his article Generalizing the Concepts Behind auto_ptr.
Below I provided the source code of TOwner<A> class and the source code of some adapters for resources of various types. They all are enclosed in awl namespace:
template <class A>
class TOwner
{
public:
  typedef A Adapter;
  typedef typename A::Handle Handle;
  static Handle Null() { return A::GetNull();}
  //The default constructor sets the stored handle to null and ownership indicator to true.
  explicit TOwner(const A & a = A()) : m_Adapter(a), m_bOwns(true),
    m_Handle(A::GetNull()) {}
  //An owner constructed with a handle to an object owns the object.
  TOwner(Handle h, const A & a = A()) : m_Adapter(a), m_bOwns(true),
    m_Handle(h) { }
  //Sets the stored handle to h and the ownership indicator to bOwns.
  TOwner(Handle h, bool bOwns, const A & a = A()) : m_Adapter(a),
    m_bOwns(bOwns), m_Handle(h) {}
  //The copy constructor sets the stored handle to the corresponding member of w and
  //transfers ownership from w.
  TOwner(const TOwner<A> & w) : m_Adapter(w.m_Adapter), m_bOwns(w.m_bOwns),
    m_Handle(w.Release()) {}
  TOwner<A> & operator = (Handle h)
  {
    if (m_Handle != h) {
      Destroy();    //delete the owned object
      m_Handle = h; //takes hold of the specified object
    }
    return *this;
  }
  TOwner<A> & operator = (const TOwner<A> & w)
  {
    if (this != &w) 
    {
      Assign(w.m_Handle, w.m_bOwns, w.m_Adapter);
      w.Release();
    }
    return *this;
  }
  void Assign(Handle h, bool bOwns, const A & a = A())
  {
    if (m_Handle != h)
    {
      //delete the owned object
      Destroy();
      m_Handle = h;
      //copy the adapter
      m_Adapter.operator = (a);
    }
    //transfer the ownership
    m_bOwns = bOwns;
  }
  ~TOwner() { Destroy();}
  //Indicates whether the stored handle is null.
  bool IsEmpty() const { return m_Handle == A::GetNull();}
  //Retrieves the stored handle value.
  Handle GetHandle() const { return m_Handle;}
  //Clears the ownership indicator returning the stored handle value.
  Handle Release() const
  {
    (const_cast<TOwner<A> *>(this))->m_bOwns = false;
    return m_Handle;
  }
  //Detaches the owned object without deleting them by setting the stored handle to null and
  //the ownership indicator to true. Returnes the handle to object to be detached.
  Handle Detach()
  {
    Handle h = m_Handle;
    CleanUp();
    return h;
  }
  //Deletes the object that it owns.
  void Destroy()
  {
    if (m_bOwns && !IsEmpty())
      AWL_VERIFY(m_Adapter.Destroy(m_Handle));
    CleanUp();
  }
  operator Handle () const { return m_Handle;}
  //The assert on operator& usually indicates a resource leak.
  //If this is really what is needed, however, call Detach() and try again.
  Handle * operator & ()
  {
    AWL_ASSERT(m_bOwns);
    AWL_ASSERT(IsEmpty());
    return &m_Handle;
  }
  Handle operator->() const
  {
    Handle h = GetHandle();
    AWL_ASSERT(h != Null());
    return h;
  }
private:
  //Declaration order of the data members is significant because Release() 
  //function used in initialization list produces a side effect.
  Adapter m_Adapter;  //adapter to operate on the owned object
  bool m_bOwns;       //ownership indicator
  Handle m_Handle;    //owned object handle
  //This member function is used instead of Detach() to avoid an operation 
  //with a dangling handle.
  void CleanUp()
  {
    m_bOwns = true;
    m_Handle = A::GetNull();
  }
};
Adapters and helper classes for working with GDI objects
template <class H>
class AGdiObject : public TAdapter< H >
{
public:
  typedef typename TAdapter<H>::Handle Handle;
  bool Destroy(Handle h) { return ::DeleteObject(h) != 0;}
};
template <class H>
class HGdiObject : public TOwner < AGdiObject < H > >
{
private:
  typedef TOwner < AGdiObject < H > > Base;
public:
  typedef typename Base::Adapter Adapter;
  typedef typename Base::Handle Handle;
  HGdiObject() {}
  HGdiObject(Handle h) : Base(h) {}
  HGdiObject(Handle h, bool bOwns) : Base(h, bOwns) {}
  HGdiObject(const HGdiObject & w) : Base(w) {}
  HGdiObject & operator=(Handle h)
  {
    Base::operator=(h);
    return *this;
  }
  HGdiObject & operator=(const HGdiObject & w)
  {
    Base::operator=(w);
    return *this;
  }
};
typedef HGdiObject<HRGN> HRegion;
typedef HGdiObject<HPEN> HPen;
typedef HGdiObject<HBRUSH> HBrush;
typedef HGdiObject<HBITMAP> HBitmap;
typedef HGdiObject<HFONT> HFont;
class TGdiSelector
{
protected:
  HDC m_hDC;
public:
  TGdiSelector(HDC hDC) : m_hDC(hDC)
  {
    AWL_ASSERT(hDC != NULL);
  }
};
template <class H>
class HGdiEntry : public TGdiSelector
{
protected:
  H m_hOldObj;
public:
  HGdiEntry(HDC hDC) : TGdiSelector(hDC)
  {
    m_hOldObj = static_cast<H>(::GetCurrentObject(hDC, HGdiObjectTraits<H>::GetObjectType()));
    AWL_ASSERT(m_hOldObj != NULL);
  }
  
  HGdiEntry(HDC hDC, H hObj) : TGdiSelector(hDC)
  {
    AWL_ASSERT(hObj != NULL);
    m_hOldObj = static_cast<H>(::SelectObject(m_hDC, hObj));
    AWL_ASSERT(m_hOldObj != NULL);
  }
  ~HGdiEntry() { AWL_VERIFY(::SelectObject(m_hDC, m_hOldObj) != NULL);}
  H operator = (H hObj)
  {
    AWL_ASSERT(hObj != NULL);
    H hOldObj = static_cast<H>(::SelectObject(m_hDC, hObj));
    AWL_ASSERT(hOldObj != NULL);
    return hOldObj;
  }
};
typedef HGdiEntry<HPEN> HPenEntry;
typedef HGdiEntry<HBRUSH> HBrushEntry;
typedef HGdiEntry<HBITMAP> HBitmapEntry;
typedef HGdiEntry<HFONT> HFontEntry;
template <class H>
class HGdiAttribute
{
private:
  typedef H Handle;
  HGdiObject<H> m_Owner;
  HGdiEntry<H> m_Selector;
public:
  HGdiAttribute(HDC hDC) : m_Selector(hDC)
  {
  }
  HGdiAttribute(HDC hDC, const HGdiObject<H> & w) : m_Owner(w), m_Selector(hDC, w) {}
  HGdiAttribute(HDC hDC, Handle h, BOOL bOwns) : m_Owner(h, bOwns), m_Selector(hDC, h) {}
  H operator = (H hObj) { m_Selector = hObj; m_Owner = hObj; return hObj;}
  const HGdiObject<H> & operator = (const HGdiObject<H> & w)
    { m_Selector = w; m_Owner = w; return m_Owner;}
  operator H () const { return m_Owner;}
  operator const HGdiObject<H> & () const { return m_Owner;}
};
typedef HGdiAttribute<HPEN> HSelPen;
typedef HGdiAttribute<HBRUSH> HSelBrush;
typedef HGdiAttribute<HBITMAP> HSelBitmap;
typedef HGdiAttribute<HFONT> HSelFont;
So, what for did I do that? The primary reason is to get rid of the annoying MFC classes such as CDC, CPen and CBrush that draw an ellipse with 7 lines of code. Furthermore, and this probably the worst, they are do not guarantee that the old GDI objects will be selected back if an exception is thrown:
// Let's assume that we have some CDC at this point CDC *pDC = GetWindowDC(); // Create a solid gren brush. CBrush brush(RGB(0, 255, 0)); // Create a solid red pen of width 2. CPen pen(PS_SOLID, 2, RGB(255,0,0)); //Now I need select my objects to DC CBrush* pOldBrush = pDC->SelectObject(&brush); CPen* pOldPen = pDC->SelectObject( &pen ); pDC->Ellipse(CRect(100, 100, 200, 200)); // and then reselect stored objects. pDC->SelectObject( pOldPen ); pDC->SelectObject(pOldBrush);
If I use HSelBrush and HSelPen I need only 3 lines:
// Let's assume that we have some HDC at this point HDC hDC = ::GetWindowDC(hSomeWnd); // Create a solid gren brush and select it to DC. awl::HSelBrush hBrush(hDC, awl::CreateSolidBrush(RGB(0, 255, 0))); // Create a solid gren brush and select it to DC awl::HSelPen hPen(hDC, awl::CreatePen(PS_SOLID, 2, RGB(0, 255, 0))); ::Ellipse(hDC, CRect(100, 100, 200, 200)); //All work is done! //I can even draw another ellipse with only 2 lines of code: // Create and select another Pen, old pen will be deselected and deleted automatically hPen = awl::CreatePen(PS_SOLID, 2, RGB(0, 0, 255)); ::Ellipse(hDC, CRect(150, 150, 250, 250)); //GDI objects will be deselected and deleted automatically by destructors of hBrush and hPen
Adapters for Windows Kernel Objects
class AKernelObject : public TAdapter<HANDLE>
{
public:
  typedef TAdapter<HANDLE>::Handle Handle;
  bool Destroy(Handle h) { return ::CloseHandle(h) != 0;}
};
typedef TOwner<AKernelObject> HKernelObject;
typedef HKernelObject HFileMapping;
typedef HKernelObject HThread;
						
