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 );
}