Listing 6: Fixed version of David Reed’s 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 —