// --------------------------------------------------------------------------- // SimpleUnboundedStack.h // // A generic unbounded stack class. (There is already a stack class in the // Standard C++ Library; this class is just an illustration of how such a // class is written from scratch!) Copying and assignment are prohibited // because this is just a simple example. A real class would have copy // constructors and an assignment operator defined. // // Stack() Constructor: declares a stack and initializes it to empty. // ~Stack() Destructor. // s.size() Returns the number of elements in the stack. // s.isEmpty() Returns whether the stack is empty. // s.push(x) Pushes x. Will throw a bad_alloc if there is no memory // available to add the element (but note that many compilers // do not implement the C++ Standard correctly and with one // of these the behavior is undefined is there is no memory). // s.pop() If not empty, pops and returns the element that was // popped, else throws a standard underflow_error. // s.peek() If not empty, returns the top element, else throws a // standard underflow_error. // --------------------------------------------------------------------------- #ifndef _SIMPLE_UNBOUNDED_STACK_H #define _SIMPLE_UNBOUNDED_STACK_H #include <stdexcept> using namespace std; // A stack object is represented as a singly-linked list of nodes. The top // of the stack is the first node. template<class T> class Stack { // A private nested class of nodes, and a neat little routine // that recursively blows away a whole linked chain of nodes. private: class Node { public: T data; Node* next; Node(T data, Node* next): data(data), next(next) {} }; static void clear(Node* n) {if (n != 0) {clear(n->next); delete n;}} // Representation. A single pointer field: private: Node* head; // Constructors and Destructors public: Stack(): head(0) {} ~Stack() {clear(head);} // Behavior public: int getSize() { int count = 0; for (Node* n = head; n != 0; n = n->next) count++; return count; } bool isEmpty() { return head == 0; } void push(T x) { head = new Node(x, head); } T pop() { if (head == 0) throw underflow_error("Cannot pop from empty stack"); Node* nodeToDelete = head; T valueToReturn = head->data; head = head->next; delete nodeToDelete; return valueToReturn; } T peek() { if (head == 0) throw underflow_error("Cannot peek into empty stack"); return head->data; } // Prohibit copying and assignment private: Stack(Stack&); Stack& operator=(Stack&); }; #endif
// --------------------------------------------------------------------------- // testunboundedstack.cpp // // A test script for the SimpleUnboundedStack class. // --------------------------------------------------------------------------- #include <iostream> #include <cassert> #include <cmath> #include <stdexcept> using namespace std; #include "SimpleUnboundedStack.h" int main(int argc, char** argv) { // Test an integer stack of testSize 8 for empty, full, and that // enqueing then dequeueing produces predicatble (LIFO) results. const int testSize = 100; Stack<int> s; assert(s.isEmpty() && s.getSize() == 0); s.push(0); assert(!s.isEmpty() && s.getSize() == 1); for (int i = 1; i < testSize; i++) { s.push(i); } assert(!s.isEmpty() && s.getSize() == testSize); for (int i = testSize - 1; i >= 0; i--) { assert(s.peek() == i); assert(s.pop() == i); } // Test underflow_errors are properly thrown on pops and peeks // when empty. Also test that if an underflow is thrown, the stack // is not disturbed, i.e., it remains empty. assert(s.isEmpty()); bool underflowHappened = false; try { s.pop(); } catch (underflow_error e) { underflowHappened = true; } assert(underflowHappened); assert(s.isEmpty()); underflowHappened = false; try { s.peek(); } catch (underflow_error e) { underflowHappened = true; } assert(underflowHappened); cout << "All tests have passed\n"; return 0; }