A Generic Vector Class Andy Wang Data Structures, Algorithms, and Generic Programming Contact Information Andy Wang (awang@cs.fsu.edu) LOV 264 Office hours: M 1:30pm – 2:30pm Th 2:00pm – 3:00pm Class website: http://www.cs.fsu.edu/~awang/courses/cop4530_f2003 Idea: A Generic Array… Of an arbitrary type (generic container) A template class Set and change the array size at runtime Index bounds checking Automatic memory management TVector<T> TVector<int> intVector(10); TVector<char> charVector(30); TVector<pair<char> > charPairVector(20); intVector.set_size(50); TVector<T> Interface Constructor(s)/destructor Operators [] = Accessor functions Set vector size Set storage capacity (reserve memory) TVector<T> Implementation A protected C array to store the array content Protected data members Size // the number of used array elements Capacity // total storage capacity A protected method that allocates memory Manage memory and data when appropriate Code Layout tvector.h tvector.cpp tvector.h #ifndef _TVECTOR_H #define _TVECTOR_H #include <stdlib.h> #include <iostream> namespace rcl { // class definition #include “tvector.cpp” // class implementation }; #endif // _TVECTOR_H tvector.cpp #ifndef _TVECTOR_CPP // now a part of the tvector.h #define _TVECTOR_CPP static const unsigned int default_capacity = 10; // operator overloads // public methods // protected methods #endif // _TVECTOR_CPP •Scope: file •Need to be initialized at the time of declaration •Cannot be changed main.cpp #include “tvector.h” // which includes tvector.cpp using namespace rcl; Tvector<int> intVector(); Class TVector<T> template <typename T> class Tvector { public: // constructors/deconstructor // operators // accessor functions protected: // data // method }; // operator overloads Class TVector<T> template <typename T> class TVector { public: // constructors/deconstructor TVector(); // default constructor TVector(size_t); TVector(const TVector<T>&); // copy constructor ~TVector(); // operators TVector<T>& operator= (const TVector<T>&); T& operator[] (size_t) const; // sizing int SetSize(size_t, const T&); int SetCapacity(size_t); size_t Size() const; size_t Capacity() const; Class TVector<T> // container class protocol int Empty() const; // return 1 if the array is empty int PushBack(const T&); // add an element to array[size] int PopBack(); // remove the element from array[size - 1] void Clear(); T& Front() const; T& Back() const; // generic display methods void Display(ostream os, char ofs = ‘\0’) const; void Dump(ostream& os) const; protected: size_t size, capacity; // array size and storage capacity T* content; // pointer to array elements static T* newarray(size_t); // allocate memory }; // operator overloads Class TVector<T> template <typename T> class TVector { public: // constructors/deconstructor TVector(); // default constructor TVector(size_t); TVector(const TVector<T>&); // copy constructor ~TVector(); // operators TVector<T>& operator= (const TVector<T>&); T& operator[] (size_t) const; // sizing int SetSize(size_t, const T&); int SetCapacity(size_t); size_t Size() const; size_t Capacity() const; Implicit copies •value = f(); •f(value); Class TVector<T> template <typename T> class TVector { public: // constructors/deconstructor TVector(); // default constructor TVector(size_t); TVector(const TVector<T>&); // copy constructor ~TVector(); // operators TVector<T>& operator= (const TVector<T>&); T& operator[] (size_t) const; // sizing int SetSize(size_t, const T&); int SetCapacity(size_t); size_t Size() const; size_t Capacity() const; Read accessor functions Class TVector<T> template <typename T> class TVector { public: // constructors/deconstructor TVector(); // default constructor TVector(size_t); TVector(const TVector<T>&); // copy constructor ~TVector(); // operators TVector<T>& operator= (const TVector<T>&); T& operator[] (size_t) const; // sizing int SetSize(size_t, const T&); int SetCapacity(size_t); size_t Size() const; size_t Capacity() const; Write accessor functions Class TVector<T> template <typename T> class TVector { public: // constructors/deconstructor TVector(); // default constructor TVector(size_t); TVector(const TVector<T>&); // copy constructor ~TVector(); // operators TVector<T>& operator= (const TVector<T>&); T& operator[] (size_t) const; // sizing int SetSize(size_t, const T&); int SetCapacity(size_t); size_t Size() const; size_t Capacity() const; Explicit copies Class TVector<T> template <typename T> class TVector { public: // constructors/deconstructor TVector(); // default constructor TVector(size_t); TVector(const TVector<T>&); // copy constructor ~TVector(); // operators TVector<T>& operator= (const TVector<T>&); T& operator[] (size_t) const; // sizing int SetSize(size_t, const T&); int SetCapacity(size_t); size_t Size() const; size_t Capacity() const; Returns a reference, so the element can be modified on the left side of an assignment Class TVector<T> // container class protocol int Empty() const; // return 1 if the array is empty int PushBack(const T&); // add an element to array[size] int PopBack(); // remove the element from array[size - 1] void Clear(); // clear the array T& Front() const; // returns array[0] T& Back() const; // returns array[size – 1] // generic display methods void Display(ostream os, char ofs = ‘\0’) const; void Dump(ostream& os) const; Debugging Functions protected: size_t size, capacity; // array size and storage capacity T* content; // pointer to array elements static T* newarray(size_t); // allocate memory }; // operator overloads Class TVector<T> // container class protocol int Empty() const; // return 1 if the array is empty int PushBack(const T&); // add an element to array[size] int PopBack(); // remove the element from array[size - 1] void Clear(); // clear the array T& Front() const; // returns array[0] T& Back() const; // returns array[size – 1] // generic display methods void Display(ostream os, char ofs = ‘\0’) const; void Dump(ostream& os) const; protected: size_t size, capacity; // array size and storage capacity T* content; // pointer to array elements static T* newarray(size_t); // allocate memory }; // operator overloads Scope: tvector.h and tvector.cpp Operator Overloads template <typename T> ostream& operator<< (ostream& os, const TVector<T>& a); template <typename T> int operator== (const TVector<T>&, const TVector<T>&); template <typename T> int operator!= (const TVector<T>&, const TVector<T>&); TVector<T> newarray() template <typename T> T* TVector<T>::newarray(size_t newcapacity) { T* Tptr = 0; if (newcapacity > 0) { Tptr = new T[newcapacity]; if (Tptr == 0) { cerr << “memory allocation failed” << endl; } } return Tptr; } A reusable routine called by constructor and size functions Constructors template <typename T> TVector<T>::TVector() : size(0), capacity(default_capacity), content(0) { content = newarray(capacity); } template <typename T> TVector<T>::TVector(unsigned int sz) : size(sz), capacity(sz) { content = newarray(capacity); } template <typename T> TVector<T>::TVector(const TVector<T>& source) : size(source.size), capacity(source.capacity) { content = newarray(capacity); for (size_t j = 0; j < size; ++j) { content[j] = source.content[j]; } } Destructor template <typename T> TVector<T>::~TVector() { delete [] content; } Debugging Routines template <typename T> void TVector<T>::Display(ostream& os, char ofc) const { size_t j; if (ofc == ‘\0’) { for (j = 0; j < size; ++j) {os << content[j];} } else { for (j = 0; j < size; ++j) {os << content[j] << ofc;} } } Debugging Routines (2) template <typename T> void TVector<T>::Dump(ostream& os) const { size_t j; if (size == 0) { os << “()”; } else { os << “(“; for (j = 1; j < size; ++j) { os << ‘,’ << content[j]; } os << “)”; } } Read Accessor Functions template <typename T> size_t TVector<T>::Size() const { return size; } template <typename T> size_t TVector<T>::Capacity() const { return capacity; } Read Accessor Functions (2) template <typename T> T& TVector<T>::Front() const { // report error and exit if size is zero return content[0]; } template <typename T> T& TVector<T>::Back() const { // report error and exit if size is zero return content[size - 1]; } Write Accessor Functions template <typename T> int TVector<T>::SetCapacity(size_t newcapacity) { if (newcapacity == 0) { // delete content and set internal states to zero return 1; } if (newcapacity != capacity) { T* newcontent = newarray(newcapacity); if (newcontent == 0) return 0; if (size > newcapacity) size = newcapacity; for (size_t j = 0; j < size; ++j) { newcontent[j] = content[j];} capacity = newcapacity; delete [] content; content = newcontent; } return 1; } Write Accessor Functions (2) template <typename T> int TVector<T>::SetSize(size_t newsize) { if (newsize > capacity) { if (SetCapacity(newsize) == 0) { return 0; } } size = newsize; return 1; } template <typename T> int TVector<T>::Clear() { SetSize(0); } Write Accessor Functions (3) template <typename T> int TVector<T>::PushBack(const T& Tval) { // expand the content array when size > capacity // expand the content array by doubling // call SetCapacity() to expand content // special case when capacity is zero—doubling zero is zero! // return 1 on success, 0 on failure } template <typename T> int TVector<T>::PopBack() { if (size == 0) return 0; --size; return 1; } Operators template <typename T> TVector<T>& TVector<T>::operator= (const TVector<T>& source) { if (this != &source) { if (source.capacity == 0) { if (capacity > 0) delete [] content; // set private data members to zero return *this; } if (capacity != source.capacity) { if (capacity > 0) delete [] content; capacity = source.capacity; content = newarray(capacity); } size = source.size; // copy content from source.content } return *this; } Operators (2) template <typename T> T& TVector<T>::operator[] (size_t j) const { if (j >= size) { cerr << “vector index out of range!” << endl; if (j >= capacity) { exit(EXIT_FAILURE); } } return content[j]; } Operator Overloads template <typename T> ostream& operator<< (ostream& os, const TVector<T>& v) { v.Display(os); return(os); } template <typename T> int operator!=(const TVector<T>& v1, const TVector<T>& v2) { return !(v1 == v2); } Operator Overloads (2) template <typename T> int operator==(const TVector<T>& v1, const TVector<T>& v2) { if (v1.Size() != v2.Size() { return 0; } for (size_t j = 0; j < v1.Size(); ++j) { if (v1[j] != v2[j]) return 0; } return 1; }