SmartPntr.cpp

#include <time.h>
#include <iostream>
#include <memory>

using namespace std;

// A 'Smart Pointer' class.
//
// This class demonstrates the following:
// 
// 1. A templated class to contain any dynamically allocated memory
// 2. A class that will optionally automatically clean up pointers 
//    (good for exception handling, to clean up allocated pointers)
// 3. A class that has operators overloaded to behave like a pointer
// 4. Normal pointer operations, with optional boundary checking
// 5. How in several instances of an object, only one is the 'owner' of a resource.
//
template <class RealType>
class Pntr
{
public:
	// Constructors and destructors
	Pntr() { Buffer=NULL; Size = Index = 0; Dynamic=false; }

	Pntr( Pntr<RealType>& Src )
	{
		Buffer=0;
		operator=(Src);
	}


	virtual ~Pntr() { Clear(); }

	// Useful functions that make it practical
	void Init( RealType* Data, int dwSize=0, bool bDynamic=true );
	void Init( int dwSize );
	void Clear() { if( Dynamic && Owner) delete[] Buffer; Buffer=NULL; Size=Index=0; }
	
	// Pointer-like operator functions
    Pntr<RealType>& operator=(Pntr<RealType>& Src)
	{
		if( &Src != this )
		{
			Clear();
			Buffer = Src.Buffer;
			Owner = Src.Owner;
			Dynamic = Src.Dynamic;
			Size = Src.Size;
			Index  = Src.Index;
			Src.Owner = false;
		}
		return( *this );
	}
    
	RealType& operator[](int dwIndex) const;
	RealType* operator++();
	RealType* operator++(int);
	RealType* operator--();
	RealType* operator--(int);
	RealType* operator+( int dwIndex ) const;
	RealType* operator-( int dwIndex ) const;
	RealType* operator->() const;
	RealType& operator*() const;

	// Note: We could add an insert and delete function, for changing the size
protected:
	RealType * Buffer; // The pointer the class wraps
	int Size;		// The size of the array, or zero if no size (no boundary checking)
	int Index;	// Current index into array for ++ and -- operators
	bool Dynamic; // If True, then memory should be deleted in destructor
	bool Owner;  // Indicates owner of block of memory.  Owners delete memory in destructor

};

template <class RealType>
void Pntr<RealType>::Init( RealType* Data, int dwSize, bool bDynamic )
{
	Clear();
	Buffer = Data;
	Size = dwSize;
	Index = 0;
	Owner = Dynamic = bDynamic;
}

template <class RealType>
void Pntr<RealType>::Init( int dwSize )
{
	Clear();
	Buffer = new RealType[dwSize];
	if( Buffer==NULL )
		throw "memory failed";
	Size = dwSize;
	Owner = Dynamic = true;
	Index=0;
}
	
template <class RealType>
RealType& Pntr<RealType>::operator[](int dwIndex) const
{
	if( Size && (Index+dwIndex >= Size ||  Index+dwIndex < 0 ))
		throw "Invalid Index";
	return( Buffer[ Index + dwIndex ] );
}

template <class RealType>
RealType* Pntr<RealType>::operator++()
{
	if( Size && Index>= Size )
		throw "Out of bounds";
	return( Buffer+ (Index++) );
}

template <class RealType>
RealType* Pntr<RealType>::operator++(int)
{
	if( Size && Index+1>= Size )
		throw "Out of bounds";
	return( Buffer +  ++Index );
}

template <class RealType>
RealType* Pntr<RealType>::operator--()
{
	if( Index < 0 )
		throw "Out of bounds";
	return( Buffer+ Index-- );
}

template <class RealType>
RealType* Pntr<RealType>::operator--(int)
{
	if( Size && Index < 0 )
		throw "Out of bounds";
	return( Buffer+ --Index );
}

template <class RealType>
RealType* Pntr<RealType>::operator-(int dwIndex) const
{
	if( Size && (Index-dwIndex>Size || Index-dwIndex<0 ) )
		throw "Out of bounds";
	return( Buffer+(Index-dwIndex) );
}

template <class RealType>
RealType* Pntr<RealType>::operator+(int dwIndex) const
{
	if( Size && (Index+dwIndex>=Size || Index+dwIndex<0 ) )
		throw "Out of bounds";
	return( Buffer+(Index+dwIndex) );
}

template <class RealType>
RealType* Pntr<RealType>::operator->() const
{
	if( Size && (Index >= Size || Index<0) )
		throw "Out of bounds";
	return( Buffer + Index );
}

template <class RealType>
RealType& Pntr<RealType>::operator*() const
{
	if( Size && (Index >= Size || Index < 0 ) )
		throw "Invalid reference";
	return( Buffer[ Index ] );
}

void main()
{
	Pntr<char> X;

	X.Init( new char[100], 100 );

	X[0]='A'; // Test the operator[]
	X[1]='B';

	try {
		X[100] = 'Z'; // Test operator[] with bad index
	} catch( char * E )
	{
		cout << E << endl;
	}
	
	try {
		*(X+100) = 'Z'; // Test the operator+ with bad index
	} catch( char * E )
	{
		cout << E << endl;
	}
	
	X++; // Test the operator++ 
	cout << *X << endl;

	X--; // Test the operator--
	cout << *X << endl;

	X--; // Go to element before array, but not a problem because we don't dereference yet.
	try
	{
		X--; // Test the operator--, and being out of bounds
	} catch( char * E )
	{
		cout << E << endl;
	}


	Pntr<struct tm> P;
	struct tm t;
	time_t Now;
	
	time(&Now);
	t = *localtime( &Now );

	P.Init( 5 );
	P[0].tm_mday=9;
	cout << P->tm_mday << endl;
	P[0] = t;

	Pntr<struct tm> Copy;
	Copy = P;


	Pntr<struct tm> Copy2( Copy );

}