SafePtr.h.

(B)Leading Edge
Simple Memory Management Classes

Jack Reeves
Listing 2. SafePtr.h.


#ifndef BEST_SAFE_PTR_H
#define BEST_SAFE_PTR_H

#include "stdext.h"

// Standard C++ headers
#include <map>
#include <stdexcept>

namespace BEST {

class SafePtrBase {
protected:
  // types
  struct Data {
    size_t    cnt;
    bool      owned;
    Data() : cnt(0), owned(false) {}
  };
  typedef std::map<void*, Data> PtrMap;

  // data
  PtrMap::iterator    _ip;

  static PtrMap              _thePtrMap;
  static PtrMap::iterator    _nullPtr;
  static bool                _initialized;
  static bool                init();

  // construct / copy / destroy
  SafePtrBase(void* p);
  SafePtrBase(SafePtrBase& other);
  ~SafePtrBase() {} // All functionality has to be handled by
                    // derived class

  // SafePtr count maintenance
  void     ref() const;
  void*    unref() const;

  // pointer operations
  void*    get(bool checked) const;
  void*    release() const;

private:
  // defined but not implemented
  SafePtrBase& operator=(const SafePtrBase&);

  // utilities
  void*    remove() const;
  void     error() const;
};

inline void
SafePtrBase::ref() const
{
  ++(*_ip).second.cnt;
}

inline void*
SafePtrBase::unref() const
{
  if (-(*_ip).second.cnt == 0) return remove();
  return null;
}

inline
SafePtrBase::SafePtrBase(SafePtrBase& other)
  : _ip(other._ip)
{
  ref();
}

inline void*
SafePtrBase::get(bool checked) const
{
  if ((*_ip).first) return ((*_ip).first);
  if (checked) error();
  return null;
}

inline void*
SafePtrBase::release() const
{
  (*_ip).second.owned = false;
  return (*_ip).first;
}

// SafePtr -
//   Note that the copy operations take a reference to a non-const
//   SafePtr. This is deliberate. It is intended to prevent a
//   const SafePtr from being assigned to a non-const SafePtr.
//   Naturally, it also makes it difficult to create a const
//   SafePtr from another const SafePtr. For that you have to get
//   the underlying pointer (const ValueType*) and then cast away
//  its const-ness.
template<typename X>
class SafePtr : private SafePtrBase {
  // types
  typedef SafePtrBase Inherited;

public:
  // types
  typedef X ValueType;

  // construct / copy / destroy
  SafePtr(X* p = null) : Inherited(p)
    {}
  SafePtr(SafePtr& other) : Inherited(other)
    {}
  template<typename Y> SafePtr(const SafePtr<Y>& other)
    : Inherited(other)
    {}
  ~SafePtr()
    { delete static_cast<X*>(Inherited::unref()); }

  SafePtr& operator=(SafePtr& other);

  // members
  X* operator->()
    { return static_cast<X*>(Inherited::get(true)); }
  const X* operator->() const
    { return static_cast<X*>(Inherited::get(true)); }

  X& operator*()
    { return *static_cast<X*>(Inherited::get(true)); }
  const X& operator*() const
    { return *static_cast<X*>(Inherited::get(true)); }

  X* get()
    { return static_cast<X*>(Inherited::get(false)); }
  const X* get() const
    { return static_cast<X*>(Inherited::get(false)); }

  X* release()
    { return static_cast<X*>(Inherited::release()); }
  const X* release() const
    { return static_cast<X*>(Inherited::release()); }

  // conversions
  operator void*()
    { return get(); }
};

template<typename X>
SafePtr<X>& SafePtr<X>::operator=(SafePtr& other)
{
  if (this != &other) {
    delete static_cast<X*>(Inherited::unref());
    _ip = other._ip;
    Inherited::ref();
  }
  return *this;
}

// the SafePtr_cast template to facilitate safe downcasts of SafePtr-based types
// X and Y are both required to be SafePtr<> types
template<typename X, typename Y>
X SafePtr_cast(Y y)
{
  if (!y) return X();  // null casts are safe
  dynamic_cast<typename X::ValueType&>(*y); //x-> bad_cast
  return X(static_cast<X::ValueType*>(y.get()));
}

} //> namespace

#endif