Listing 6: Fixed version of David Reeds stack class from Listing 3
#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