// File: Vec.h // Author: Chuck Stewart, revised from the original by Koenig and Moo. // Purpose: Illustrate a simple implementation of the vector class. // // Here are some details (see the associated lecture notes for a more // complete discussion): // // . The class is templated, just like the vector class is in the // standard library. This creates the need for new notation in // the class declaration and additional syntactic complexity in // the member functions. T, the template parameter, is treated // like an ordinary type. One important difference from ordinary // (non-templated) classes is that the there is no separate .cpp // file and no separate compilation. This header file must be // #included wherever it is needed. // // . This class uses a dynamically allocated array (of T's) as its // underlying implementation. The member variable m_data is a // pointer to the start of the array. The member variable m_size // indicates the size of the array, in the vector sense of the // word "size". This is the number of currently used array // locations. The third member variable, m_alloc, indicates the // size of the currently allocated array. It is important that // the code always ensures that m_size <= m_alloc and when a // push_back or resize call would violate this condition, a new // and larger array is reallocated and the old contents are // copied. // // . Finally, the code here, uses new and delete for its dynamic // memory allocation instead of the more sophisticated allocators // discussed in Section 11.5 of the Koenig and Moo text. There // are some technical reasons why allocators are better, but we // will use new and delete for now. #ifndef Vec_h_ #define Vec_h_ template class Vec { public: // Typedefs typedef T* iterator; typedef const T* const_iterator; typedef unsigned int size_type; public: // Constructors, destructors and assignment operator Vec() { this->create(); } explicit Vec(size_type n, const T& t = T()) { this->create(n, t); } Vec(const Vec& v) { copy(v); } ~Vec() { delete [] m_data; } Vec& operator=( const Vec& v ); public: // Member functions and other operators T& operator[] ( size_type i ) { return m_data[i]; } const T& operator[] ( size_type i ) const { return m_data[i]; } void push_back(const T& t); iterator erase( iterator p ); void resize( size_type n, const T& fill_in_value = T()); void clear() { delete [] m_data; create(); } bool empty() const { return m_size == 0; } size_type size() const { return m_size; } public: // Iterator operations --- these are just pointer operations iterator begin() { return m_data; } const_iterator begin() const { return m_data; } iterator end() { return m_data + m_size; } const_iterator end() const { return m_data + m_size; } private: T* m_data; // Pointer to first location in the allocated array size_type m_size; // Number of elements stored in the vector size_type m_alloc; // Number of array locations allocated. m_size <= m_alloc private: void create(); void create(size_type n, const T& val); void copy( const Vec& v ); }; // Create an empty vector (null pointers). template void Vec::create() { m_data = 0; // Null pointer m_size = m_alloc = 0; // No memory locations } // Create a vector with size n, each location having the given value template void Vec::create( size_type n, const T& val) { m_data = new T[n]; m_size = m_alloc = n; for ( T* p = m_data; p != m_data + m_size; ++p ) *p = val; } // Assign one vector to another, avoiding duplicate copying. template Vec& Vec :: operator=( const Vec& v ) { if ( this != &v ) // avoid doing anything for self-assignment { delete [] m_data; this -> copy( v ); } return *this; } // Create the vector as a copy of the given vector. To be written // during lecture. template void Vec :: copy( const Vec& old ) { } // Add a value to the back of the current vector, increasing its // size by 1. Before doing this actual operator, however, check to // see if the size has reached the end of the allocation. If so, // double the size of the allocated array, copying the old values to // the new array. template void Vec :: push_back( const T& val ) { if ( m_alloc == m_size ) { // Do memory stuff } m_data[m_size] = val; ++m_size; } // Copy each entry of the array above the iterator (this is just a T* // --- a pointer to a T) down one location. Return the iterator, // which will have the same value, but point to a different location. template typename Vec :: iterator Vec :: erase( iterator p ) { } // Change the size of the vector to n. If n is less than or equal to // the current size, just change the size. If n is greater than the // current size, the new slots must be filled in with the given // value. Re-allocation should occur only if necessary. push_back // should not be used. template void Vec :: resize( size_type n, const T& fill_in_value ) { } #endif