Original Post
I needed a smart pointer for my engine, and in the grand tradition of reckless DIY, I decided to write one myself. I know boost and loki are full featured and debugged...but I wanted something lightweight, contained in one header. If anyone wants to use this for a project under any license, feel free. I'd really appreciate any feedback and/or suggestions. -Alex
struct X { };
struct Y : public X { } ;
ptr<X> x = new X;
ptr<Y> y = new Y;
y = x;
x = new X;
if (x) printf("is valid");
if (x && y) printf("both valid");
if (x == y) printf("point to same");
x->func;
X x2 = *x;
/*
* ptr - A non-intrusive reference counted pointer.
* Written by Alex Rubinsteyn (rubnstyn@uiuc.edu)
* Many ideas borrowed from Yonat Sharon and
* Andrei Alexandrescu.
*
* Use freely, just give credit.
*/
#ifndef lutefisk_ptr_H
#define lutefisk_ptr_H
template <typename X>
class ptr
{
public:
typedef X element_type;
/*
ptr needs to be its own friend so ptr<X> and ptr<Y> can access
each other's private data members
*/
friend class ptr;
/*
default constructor
- don't create counter
*/
ptr() : rawPtr(0), itsCounter(0)
{
}
/*
Construct from a raw pointer
*/
ptr(X* raw) : rawPtr(0), itsCounter(0)
{
if (raw)
{
rawPtr = raw;
itsCounter = new counter(1);
}
}
template <typename Y>
ptr(Y* raw) : rawPtr(0), itsCounter(0)
{
if (raw)
{
rawPtr = static_cast<X*>( raw );
itsCounter = new counter(1);
}
}
/*
Copy constructor
*/
ptr(const ptr<X>& otherPtr)
{
acquire( otherPtr.itsCounter );
rawPtr = otherPtr.rawPtr;
}
template <typename Y>
ptr(const ptr<Y>& otherPtr) : rawPtr(0), itsCounter(0)
{
acquire( static_cast<counter*> (otherPtr.itsCounter) );
rawPtr = static_cast<X*>( otherPtr.GetRawPointer());
}
/*
Destructor
*/
~ptr()
{
release();
}
/*
Assignment to a raw pointer
This is dangerous, because the pointer
could be in use elsewhere
*/
ptr& operator=(X* raw)
{
if (raw && raw != rawPtr)
{
release();
itsCounter = new counter(1);
rawPtr = raw;
}
return *this;
}
template <typename Y>
ptr& operator=(Y* raw)
{
if ( raw && (X*) raw != rawPtr )
{
release();
itsCounter = new counter(1);
rawPtr = static_cast<X*> (raw);
}
return *this;
}
/*
Assignment to another ptr
*/
ptr& operator=(const ptr<X>& otherPtr)
{
if (this != &otherPtr)
{
release();
acquire(otherPtr.itsCounter);
rawPtr = otherPtr.rawPtr;
}
return *this;
}
template <typename Y>
ptr& operator=(const ptr<Y>& otherPtr)
{
if ( this != (ptr<X>*) &otherPtr )
{
release();
acquire( static_cast<counter*>(otherPtr.itsCounter) );
rawPtr = static_cast<X*> (otherPtr.GetRawPointer());
}
return *this;
}
/*
Member Access
*/
X* operator->() const
{
return GetRawPointer();
}
/*
Dereference the pointer
*/
X& operator* () const
{
return *GetRawPointer();
}
/*
Conversion/casting operators
*/
template <typename Y>
operator Y*() const
{
return static_cast<Y*>(rawPtr);
}
template <typename Y>
operator const Y*() const
{
return static_cast<Y*>(rawPtr);
}
operator bool() const
{
return IsValid();
}
unsigned int GetCount() const
{
return count;
}
/*
Provide access to the raw pointer
*/
X* GetRawPointer() const
{
if (rawPtr == 0) printf("\nPOINTER_ERROR: getting null pointer");
return rawPtr;
}
const X* GetConstPointer() const
{
return GetRawPointer();
}
bool IsUnique() const
{
if (itsCounter && itsCounter->count == 1) return true;
else return false;
}
bool IsValid() const
{
if (itsCounter && rawPtr) return true;
else return false;
}
private:
X* rawPtr;
struct counter
{
counter(unsigned c = 1) : count(c) {}
unsigned count;
};
counter* itsCounter;
// increment the count
void acquire(counter* c)
{
itsCounter = c;
if (c)
{
(c->count)++;
}
}
// decrement the count, delete if it is 0
void release()
{
if (itsCounter)
{
(itsCounter->count)--;
if (itsCounter->count == 0)
{
delete rawPtr;
delete itsCounter;
}
}
itsCounter = 0;
rawPtr = 0;
}
};
template <typename X, typename Y>
bool operator<(const ptr<X>& lptr, const ptr<Y>& rptr)
{
return (lptr.GetConstPointer() < static_cast<const X*> rptr.GetConstPointer() );
}
template <typename X, typename Y>
bool operator<(const ptr<X>& lptr, Y* raw)
{
return (lptr.GetConstPointer() < static_cast<const X*>(raw) );
}
template <typename X, typename Y>
bool operator==(const ptr<X>& lptr, const ptr<Y>& rptr)
{
return lptr.GetConstPointer() == static_cast<const X*>( rptr.GetConstPointer() ) ;
}
template <typename X, typename Y>
bool operator==(const ptr<X>& lptr, Y* raw)
{
return (lptr.GetConstPointer() == static_cast<const X*>(raw) );
}
template <typename X>
bool operator==(const ptr<X>& lptr, int num)
{
if (num == 0 && !lptr.IsValid()) return true;
else return false;
}
template <typename X, typename Y>
bool operator!=(const ptr<X>& lptr, const ptr<Y>& rptr)
{
return ( !operator==(lptr, rptr) );
}
template <typename X, typename Y>
bool operator!=(const ptr<X>& lptr, Y* raw)
{
return ( !operator==(lptr, raw) );
}
template <typename X>
bool operator!=(const ptr<X>& lptr, int num)
{
return (!operator==(lptr, num) );
}
template <typename X, typename Y>
bool operator&&(const ptr<X>& lptr, const ptr<Y>& rptr)
{
return lptr.IsValid() && rptr.IsValid();
}
template <typename X>
bool operator&&(const ptr<X>& lptr, bool rval)
{
return lptr.IsValid() && rval;
}
template <typename X>
bool operator&&(bool lval, const ptr<X>& rptr)
{
return lval && rptr.IsValid();
}
template <typename X, typename Y>
bool operator||(const ptr<X>& lptr, const ptr<Y>& rptr)
{
return lptr.IsValid() || rptr.IsValid();
}
template <typename X>
bool operator||(const ptr<X>& lptr, bool rval)
{
return lptr.IsValid() || rval;
}
template <typename X>
bool operator||(bool lval, const ptr<X>& rptr)
{
return lval || rptr.IsValid();
}
template <typename X>
bool operator!(const ptr<X>& p)
{
return (!p.IsValid());
}
#endif // ptr_H