На этом шаге мы приведем пользовательскую реализацию стека.
Стандартный класс stack<> ставит на первое место не удобство и безопасность, а скорость работы. Поэтому вашему вниманию предлагается нестандартная реализация стека. Она обладает двумя преимуществами:
Кроме того, из реализации были исключены операции, лишние для рядового пользователя стеков (например, операции сравнения). Полученный класс стека приведен ниже.
// ************************************************************ // * Stack.hpp // * - более удобный и безопасный класс стека // * ************************************************************ #ifndef STACK_HPP #define STACK_HPP #include <deque> #include <exception> template <class T> class Stack { protected: std::deque<T> c; // Контейнер для хранения элементов public: /* Класс исключения, генерируемого функциями pop() и top() * при пустом стеке */ class ReadEmptyStack : public std::exception { public: virtual const char* what() const throw() { return "read empty stack"; } }; // Количество элементов typename std::deque<T>::size_type size() const { return c.size(); } // Проверка пустого стека bool empty() const { return c.empty(); } // Занесение элемента в стек void push (const T& elem) { c.push_back(elem); } // Извлечение элемента из стека с возвращением его значения T pop () { if (c.empty()) { throw ReadEmptyStack(); } T elem(c.back()); c.pop_back(); return elem; } // Получение значения верхнего элемента T& top () { if (c.empty()) { throw ReadEmptyStack(); } return c.back(); } }; #endif // STACK_HPP
При использовании этого класса стека пример из 329 шага можно записать в следующем виде:
//--------------------------------------------------------------------------- #include <vcl.h> #include <iterator> #include <iostream> #include "Stack.hpp" // Использование нестандартного класса стека #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } int main() { try { Stack<int> st; // Занесение трех элементов в стек st.push(1); st.push(2); st.push(3); // Извлечение и вывод двух элементов из стека cout << ToRus("Извлечение и вывод двух элементов из стека: \n"); cout << st.pop() << ' '; cout << st.pop() << ' '; cout << endl; // Модификация верхнего элемента st.top() = 77; // Занесение двух новых элементов st.push(4); st.push(5); // Извлечение одного элемента без обработки st.pop(); // Извлечение и вывод трех элементов // - ОШИБКА: одного элемента не хватает cout << ToRus("Извлечение и вывод трех элементов:\n"); cout << st.pop() << ' '; cout << st.pop() << endl; cout << st.pop() << endl; } catch (const exception& e) { cerr << "EXCEPTION: " << e.what() << endl; } getch(); return 0; } //---------------------------------------------------------------------------
При последнем вызове рор() намеренно допущена ошибка. В отличие от стандартного класса стека с неопределенным поведением наш класс генерирует исключение. Результат выполнения программы выглядит так:
Рис.1. Результат работы приложения
Со следующего шага мы начнем рассматривать очереди.