Click here to Skip to main content
15,896,063 members
Articles / Desktop Programming / MFC

Another Enum Viewer

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
22 Oct 20015 min read 83K   1.3K   19  
An article on the usage and design of another Enum Viewer
// refptr.h:  
//     reference-counting "pointer" object for handling pointers
//     to reference-counted objects implementing the following interface:
//         void ref()      increment refcount
//         void deref()    decrement refcount
//         unsigned nref()	get refcount

#ifndef INCL_REFPTR_H
#define INCL_REFPTR_H

#include "JLCast.h"
#include <assert.h>

////////////////////////////////////////////////////////////////////////////
// Generic reference-counter class.  Inheriting from this is an easy way to
// get the functionality required by refcnt_ptr<T>.  However, that is not
// necessary, since refcnt_ptr<T> is a template and you can implement the
// ref(), deref(), and nref() methods however you like.  Note that ref() and
// deref() both must work for const objects.
////////////////////////////////////////////////////////////////////////////
class RefCount
{
public:
   // default ctor
   RefCount() : refcount(0) {}
   // copy ctor *does not* copy refcount value
   RefCount(const RefCount&) : refcount(0) {}
   // assignment operator *does not* copy refcount
   RefCount& operator=(const RefCount&) { return *this; }

   // Public interface
   // Allow refcount operations on const objects
   void ref() const { ((RefCount*)this)->refcount++; }
   void deref() const { ((RefCount*)this)->refcount--; }
   unsigned short nref() const { return refcount; }

protected:
   // Only let destruction occur via derived class, because
   // this is not a virtual dtor
   ~RefCount() {}
private:
   unsigned short refcount;
};

// Reference-counter base class with virtual dtor, so that objects
// may be deleted by pointer-to-VRefCount
class VRefCount : public RefCount
{
public:
   // no need to implement ctor or operator=, as memberwise copy is sufficient
   virtual ~VRefCount() {}
};

////////////////////////////////////////////////////////////////////////////
// Const reference-counted pointer
////////////////////////////////////////////////////////////////////////////

// forward declarations
template <class T> class refcnt_ptr;
template <class T> class refcnt_ptrI;
template <class T> class refcnt_cptrI;

////////////////////////////////////////////////////////////////////////////
// const ref-counted ptr
template<class T> class refcnt_cptr {
   friend class refcnt_ptr<T>;

public:
   // Basic ctor
   refcnt_cptr(const T* ptr_ = 0);

   // copy ctor
   refcnt_cptr(const refcnt_cptr& rhs);

   // dtor
   ~refcnt_cptr();

   // Access to pointer
   const T* get() const { return ptr; }
   const T* operator->() const { return get(); }
   const T& operator*() const { return *get(); }
  
   // assignment from dumb pointer
   refcnt_cptr& operator=(const T* rhs);

   // Assignment from smart const pointer (also supports non-const)
   refcnt_cptr& operator=(const refcnt_cptr& rhs);

   // Comparison (also supports comparison to non-const ptr)
   bool operator==(const refcnt_cptr& rhs) const
   {
      return ptr == rhs.get();
   }
   bool operator!=(const refcnt_cptr& rhs) const
   {
      return ptr != rhs.get();
   }
   // Used for ordering in maps
   bool operator<(const refcnt_cptr& rhs) const
   {
      return ptr < rhs.get();
   }

private:
   // Decrement refcount on pointed-to object and delete if zero
   void release();
   void ref() const;
   void deref() const;
   const T* ptr;
};

//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//

template<class T>
inline refcnt_cptr<T>::refcnt_cptr(const T* ptr_) : ptr(ptr_) 
{ 
   if (ptr) ref(); 
}

template<class T>
inline refcnt_cptr<T>::refcnt_cptr(const refcnt_cptr& rhs) : ptr(rhs.get()) 
{ 
   if (ptr) ref();
}

template<class T>
inline refcnt_cptr<T>::~refcnt_cptr() 
{
   release(); 
}

template<class T>
inline refcnt_cptr<T>& refcnt_cptr<T>::operator=(const T* rhs)
{
   // works for this->ptr == rhs
   if (rhs)
   {
      rhs->ref();
   }
   release();
   ptr = rhs;
   return *this;
}

template<class T>
inline refcnt_cptr<T>& refcnt_cptr<T>::operator=(const refcnt_cptr& rhs)
{
   // works for rhs==this
   if (rhs.get())
   {
      rhs.ref();
   }
   release();
   ptr = rhs.get();
   return *this;
}

template<class T>
inline void refcnt_cptr<T>::release()
{ 
   if (ptr) 
   { 
      if (ptr->nref() == 1)
      {
         // allow deletion of const object
         delete CONST_CAST(T*, ptr);
      } else {
         deref(); 
      }
      ptr = 0;
   }
}

template<class T>
inline void refcnt_cptr<T>::ref() const 
{ 
   ptr->ref(); 
}

template<class T>
inline void refcnt_cptr<T>::deref() const 
{
   ptr->deref();
}

////////////////////////////////////////////////////////////////////////////
// non-const refcounted ptr -- note that a "const refcnt_ptr<T>" is *not* the
// same as a "refcnt_cptr<T>" -- the former still allows access to
// the non-const pointed-to object
////////////////////////////////////////////////////////////////////////////
template<class T> class refcnt_ptr : public refcnt_cptr<T>
{
public:
   // basic ctor
   refcnt_ptr(T* ptr_ = 0);

   // copy ctor
   // Don't allow construction from refcnt_cptr
   refcnt_ptr(const refcnt_ptr& rhs);
   
   // assignment operators
   // Don't allow assignment from refcnt_cptr
   refcnt_ptr& operator=(const refcnt_ptr& rhs);
   refcnt_ptr& operator=(T* rhs);

   // Access operators (non-const access to object)
   T* get() const { return CONST_CAST(T*, ptr); }
   T* operator->() const { return get(); }
   T& operator*() const { return *get(); }
};

//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//

template<class T>
inline refcnt_ptr<T>::refcnt_ptr(T* ptr_) : 
   refcnt_cptr<T>(ptr_) 
{}

template<class T>
inline refcnt_ptr<T>::refcnt_ptr(const refcnt_ptr& rhs) : 
   refcnt_cptr<T>(rhs.get()) 
{}

template<class T>
inline refcnt_ptr<T>& refcnt_ptr<T>::operator=(const refcnt_ptr& rhs)
{
   refcnt_cptr<T>::operator=(rhs);
   return *this;
}

template<class T>
inline refcnt_ptr<T>& refcnt_ptr<T>::operator=(T* rhs)
{
   refcnt_cptr<T>::operator=(rhs);
   return *this;
}


////////////////////////////////////////////////////////////////////////////
// Implementation of "incomplete" ref-counted pointers.  These are really
// ref-counted pointers to VRefCount, which implements rec-counting and
// and has a virtual destructor.
// These are used so that:
// 1) A refcounted pointer to an object can be used, passed by value,
//    without knowing the object implementation.
// 2) Use of said incomplete refcounted pointer will still delete the
//    object when the refcount drops to zero.
// 3) Casting between the incomplete type and the complete type can
//    be done implicitly.
// 4) The types of incomplete refcounted pointers are distinct.
//
// Since casting between T and VRefCount is performed implicitly,
// T ***MUST*** be derived from VRefCount, and VRefCount must be the
// first base class, e.g.:
//     class MyClass : public VRefCount, public OtherClass {};
////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////
// "Incomplete" const refcounted pointer
// This implements the non-inherited methods and the conversions
// between complete and incomplete refcounted pointers.
////////////////////////////////////////////////////////////////////////////
template <class T> 
class refcnt_cptrI : public refcnt_cptr<VRefCount>
{
private:
   typedef refcnt_cptr<VRefCount> myBase;
public:
   // basic ctor
   refcnt_cptrI(const T* ptr_ = 0) : 
      myBase( REINTERPRET_CAST(const VRefCount*, ptr_) ) 
   {}

   // copy ctor
   refcnt_cptrI(const refcnt_cptrI& rhs) : 
      myBase( REINTERPRET_CAST(const VRefCount*, rhs.get()) ) 
   {}
   
   // assignment operators
   refcnt_cptrI& operator=(const refcnt_cptrI& rhs)
   {
      refcnt_cptr<VRefCount>::operator=(rhs);
      return *this;
   }
   refcnt_cptrI& operator=(const T* rhs)
   {
      refcnt_cptr<VRefCount>::operator=(REINTERPRET_CAST(const VRefCount*, rhs));
      return *this;
   }

   // Conversion to/from complete types
   const T* get() const { return REINTERPRET_CAST(const T*, myBase::get()); }
   operator const T* () const { return get(); }
   const T* operator->() const;
   const T& operator*() const { return *(operator const T*()); }

   // The body of this is specified separately; otherwise MSVC++
   // (and probably other compilers) instantiates it even if not called.
   // ctor from complete refcounted ptr
   refcnt_cptrI(const refcnt_cptr<T>&);
};

//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//

template <class T> 
inline refcnt_cptrI<T>::refcnt_cptrI(
   const refcnt_cptr<T>& rhs
) :
   myBase((const VRefCount *)rhs.get())
{
}

template <class T> 
inline const T* 
refcnt_cptrI<T>::operator->() const 
{
   // Since operator-> is presumably only used when you have the complete
   // type, then use STATIC_CAST here to enforce some type checking.
   // Furthermore, we can add an assertion to make sure that the static
   // cast matches the reinterpret cast used elsewhere.
   assert(STATIC_CAST(const T*, myBase::get()) == REINTERPRET_CAST(const T*, myBase::get()));
   return get();
}

////////////////////////////////////////////////////////////////////////////
// "Incomplete" non-const refcounted pointer
// This implements the non-inherited methods and the conversions
// between complete and incomplete refcounted pointers.
////////////////////////////////////////////////////////////////////////////
template <class T> 
class refcnt_ptrI : public refcnt_ptr<VRefCount>
{
private:
   typedef refcnt_ptr<VRefCount> myBase;
public:
   // basic ctor
   refcnt_ptrI(T* ptr_ = 0) : 
      myBase( REINTERPRET_CAST(VRefCount*, ptr_) ) 
   {}
   // copy ctor
   refcnt_ptrI(const refcnt_ptrI& rhs) : 
      myBase( REINTERPRET_CAST(VRefCount*, rhs.get()) ) 
   {}
   
   // assignment operators
   refcnt_ptrI& operator=(const refcnt_ptrI& rhs)
   {
      refcnt_ptr<VRefCount>::operator=(rhs);
      return *this;
   }
   refcnt_ptrI& operator=(T* rhs)
   {
      refcnt_ptr<VRefCount>::operator=(REINTERPRET_CAST(VRefCount*, rhs));
      return *this;
   }

   // Conversion to/from complete types
   T* get() const { return REINTERPRET_CAST(T*, myBase::get()); }
   operator T* () const { return get(); }
   T* operator->() const;
   T& operator*() const { return *(operator T*()); }

   // The body of this is specified separately; otherwise MSVC++
   // (and probably other compilers) instantiates it even if not called.
   // ctor from complete refcounted ptr
   refcnt_ptrI(const refcnt_ptr<T>&);
};

//
// This are outside of the class because MSVC++ instantiates everything
// declared in the class even if it isn't used
//

template <class T> 
inline refcnt_ptrI<T>::refcnt_ptrI(
   const refcnt_ptr<T>& rhs
) :
   refcnt_ptr<VRefCount>((VRefCount *)rhs.get())
{
}

template <class T> 
inline T* 
refcnt_ptrI<T>::operator->() const 
{
   // Since operator-> is presumably only used when you have the complete
   // type, then use STATIC_CAST here to enforce some type checking.
   // Furthermore, we can add an assertion to make sure that the static
   // cast matches the reinterpret cast used elsewhere.
   assert(STATIC_CAST(T*, myBase::get()) == REINTERPRET_CAST(T*, myBase::get()));
   return get();
}



#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions