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