/*----------------------------------------------------------------*/
/* This file can be saved to your machine (almost) as you see it */
/* by doing a "Save As..." from the File menu of your browser. */
/* */
/* For this to work, you must TYPE a filename with .txt as the */
/* file extent. (Simply selecting .txt as the file type */
/* doesn't seem to be sufficient.) Remove the .txt extension */
/* once the file is saved. (IE inserts the page title as the */
/* first line, which must be removed also.) */
/*----------------------------------------------------------------*/
// Author: Hannah C. Tang (hctang@cs)
//
// Implementation for a templated array class with bounds checking
#include
<iostream>
#include
<cassert>
using namespace std;
#include
"Array.hh"
//
// Overloaded constructor. Note the use of the member initialization list
// to initialize m_capacity before its use in the body of the constructor
//
template< typename T >
Array< T >::Array( int
initCapacity )
: m_capacity( initCapacity )
{
m_pData = new T[ m_capacity ];
}
//
// Copy constructor. Uses the member function Copy(). Note that there
// is no need to delete m_pData prior to setting it to NULL in the
// memberwise initialization list. Why do you think this is the case?
//
template< typename T >
Array< T >::Array( const
Array& other )
: m_pData( NULL )
{
Copy( other );
}
//
// Assignment operator. Uses the member functions Copy() and Destroy().
// Remember that it is necessary to check against self-assignment.
// Why does the assignment operator need to delete m_pData but the
// copy constructor does not?
//
template< typename T >
const
Array< T >&
Array< T >::operator=( const
Array& other )
{
if
( this != &other )
{
Destroy(); // Delete existing memory
Copy( other ); // Copy 'other' into 'this'
}
return
*this;
}
//
// Destructor. Uses the member function Destroy()
//
template< typename T >
Array< T >::~Array( void
)
{
Destroy();
}
//
// Indexing operator, const version
//
template< typename T >
const
T&
Array< T >::operator[]( int
index ) const
{
// Invalid index. Note that I'm using >=, not >
// Asserting a "NOT'ed string" will always be false, but
// also allows for an informative error message
assert( index >= 0 && index < m_capacity
&& "Index out of bounds on operator[]!" );
return
m_pData[ index ];
}
//
// Indexing operator, non-const version
//
template< typename T >
T&
Array< T >::operator[]( int
index )
{
// Invalid index. Note that I'm using >=, not >
if
( index < 0 || index >= m_capacity )
{
// Asserting "NOT'ed string" will always be false but
// also allows for an informative error message
assert( index >= 0 && index < m_capacity
&& "Index out of bounds on operator[]!" );
}
return
m_pData[ index ];
}
//
// GetCapacity. Gets the current capacity of the array
//
template< typename T >
int
Array< T >::GetCapacity( void
)
{
return
m_capacity;
}
//
// Copy. Copies its argument into the current instance
//
template< typename T >
void
Array< T >::Copy( const
Array& other )
{
m_capacity = other.m_capacity;
// Create an array that is the same size as 'other', and
// copy other's data over
m_pData = new T[ m_capacity ];
for
( int
i = 0; i < m_capacity; i++ )
{
m_pData[ i ] = other.m_pData[ i ];
}
}
//
// Destroy. Cleans up the current instance (deletes dynamic memory, etc)
//
template< typename T >
void
Array< T >::Destroy( void
)
{
delete [] m_pData; // C++ trivia: deleting NULL is defined to be a no-op
// Note that I'm using delete[], not delete. Remember:
// if you use new[], it *must* be matched with delete[]
m_pData = NULL;
m_capacity = 0;
}