#ifndef STACK_H
#define STACK_H
#include <algorithm> // for swap
template<class T>
class Stack
{
unsigned nelems;
int top;
T* v;
public:
unsigned Size();
void Push(T);
T Pop();
Stack();
~Stack();
Stack( const Stack& );
Stack& operator=(const Stack&);
bool Consistent() const;
};
template<class T>
Stack<T>::Stack()
{
top = -1;
v = new T[nelems=10];
}
template<class T>
Stack<T>::Stack( const Stack<T>& s )
{
v = new T[nelems = s.nelems];
if( s.top > -1 ) {
// 20000408 bstanley fix 7 cater for
// exceptions in T::operator=
try {
for( top = 0; top <= s.top; top++ )
v[top] = s.v[top];
} catch(...) {
delete [] v;
throw;
}
top--;
} else {
// 20000408 bstanley fix 1
top = -1;
}
}
template<class T>
Stack<T>::~Stack()
{
delete[] v;
}
template<class T>
void Stack<T>::Push( T element )
{
top++;
// 20000408 bstanley fix 6 - commit or rollback semantics.
try {
if( top == nelems-1 ) {
T* new_buffer = new T[nelems+=10];
// 20000408 bstanley fix 5 -
// added exception handling to prevent leak.
try {
for( int i = 0; i < top; i++ ) {
new_buffer[i] = v[i];
}
} catch( ... ) {
delete [] new_buffer;
throw;
}
delete [] v;
v = new_buffer;
}
v[top] = element;
} catch( ... ) {
--top;
throw;
}
}
template<class T>
T Stack<T>::Pop()
{
if( top < 0 ) throw "pop on empty stack";
return v[top--];
}
template<class T>
unsigned Stack<T>::Size()
{
return top+1;
}
template<class T>
Stack<T>& Stack<T>::operator=( const Stack<T>& s )
{
// 20000408 bstanley fix 3
if( this != &s ) {
// 20000408 bstanley fix 4 re-written to be exception safe.
T* v_new = new T[nelems = s.nelems];
if( s.top > -1 ) {
try {
for( top = 0; top <= s.top; top++ ) {
v_new[top] = s.v[top];
}
--top;
} catch(...) {
delete [] v_new;
throw;
}
} else {
// 20000408 bstanley fix 2
top = -1;
}
// now swap
swap( v, v_new ); // can't throw.
delete [] v_new;
}
return *this;
}
template<class T>
bool
Stack<T>::Consistent() const
{
// Weak check
return (top < int(nelems)) and (v != 0);
}
#endif // STACK_H
End of Listing