A Generic Vector Class Andy Wang Data Structures, Algorithms, and Generic Programming

advertisement
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;
}
Download