// Author: Hannah C. Tang (hctang@cs) // // Implementation for a templated array class with bounds checking #include #include 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; }