Skip to main content
gamedev.net
🔒 Locked

Smart Pointer

Started by cypherx 1 reply 800+ views
Original Post
cypherx
cypherx
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



cypherx
cypherx
I guess it's a bit much to expect people to read all that source. I do have a specific question that won't require nearly as much effort to answer. To handle the situation ptr = ptr I made the assignment templated with a static_cast to the ptr's type. This works for downcasting just fine...but also allows unchecked upcasting. Are there any not-obvious problems I'll run into because of this cast?

Thanks,
Alex
smart_idiot
smart_idiot
You could probably just use dynamic_cast to convert the pointer to the classes's type, and then throw an exception if it fails.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.