|
Программирование >> Разработка устойчивых систем
объекты string, вставляемые в контейнер с элементами string - во всех случаях, кроме последнего, используется вектор vector<string> (также можно было объединить результаты в string). В остальном итератор Tokenlterator работает так же, как любой другой. При определении двустороннего итератора (а следовательно, и итератора произвольного доступа) вы можете бесплатно получить обратные итераторы при помощи адаптера std::reverse iterator. Если в программе уже определен итератор для контейнера с двусторонним перебором, вы можете получить обратный итератор на базе прямого итератора. Для этого в класс контейнера включается фрагмент вида Предполагается, что iterator -- вложенный тип итератора typedef std::reverse iterator<iterator> reverse iterator: reverse iterator rbeginO (return reverse iterator(end()): reversejterator rendO (return reverse iterator(begin()): Адаптер std::reverseJterator выполняет всю работу за вас. Например, при разыменовании обратного итератора оператором * он автоматически уменьшает временную копию своего прямого итератора, чтобы вернуть правильный элемент, потому что обратные итераторы логически установлены на одну позицию за тем элементом, на который они ссылаются. Стек Контейнер stack, наряду с queue и priority queue, относится к категории контейнерных адаптеров. Это означает, что он адаптирует один из базовых последовательных контейнеров для хранения своих данных. Впрочем, этот термин лишь вносит некоторую путаницу - тот факт, что эти контейнеры называются адаптерами , имеет значение разве что с точки зрения создания библиотеки. При практическом применении важно не то, как называется контейнер, а то, что он решает вашу задачу. Возможно, в отдельных случаях было бы полезно знать о возможности выбора альтернативной реализации или построения адаптера на базе существующего объекта контейнера, но обычно адаптеры не наделяются соответствующей функциональностью. И если в других книгах тот или иной контейнер постоянно именуется адаптером, мы будем напоминать об этом обстоятельстве лишь тогда, когда оно приносит реальную пользу. В следующем примере продемонстрированы три варианта реализации stack<string>. В первом (стандартном) варианте используется дек, а в двух других - вектор и список: : C07:Stackl.cpp Работа со стеком STL linclude <fstream> linclude <iostream> linclude <list> linclude <stack> linclude <string> linclude <vector> using namespace std: Переставьте комментарии, чтобы использовать другую версию стека, typedef stack<string> Stackl: По умолчанию: deque<string> typedef stack<string. vector<string> > Stack2: typedef stack<str1ng. list<string> > Stack3: int mainO { ifstream inCStackl.cpp ): Stackl textlines: Попробуйте использовать другие версии. Чтение файла и сохранение строк в стеке: string line: while(getline(in. line)) textlines.push(line + \n ): Вывод строк и их извлечение из стека: while(! textl ines. emptyO) { cout textlines.topO: textl ines.popO: } III:- Если раньше вы работали с другими классами стеков, функции top() и рор() могут показаться противоестественными. Вместо верхнего элемента стека, как можно было бы ожидать, функция рор() возвращает void. Если вас интересует значение верхнего элемента, получите ссылку на него функцией top(). Такой вариант более эффективен, поскольку традиционная функция рор() возвращает значение вместо ссылки, а для этого необходим вызов копирующего конструктора. Что еще важнее, такое решение безопасно по отношению к исключениям (эта тема обсуждалась в главе 1). Если бы функция рор() одновременно изменяла состояние стека и пыталась вернуть верхний элемент, исключение в копирующем конструкторе элемента могло бы привести к его потере. При использовании шаблона stack (или приоритетной очереди priority queue, о которой речь пойдет далее) можно эффективно ссылаться на элемент top() сколько угодно раз, а затем удалить верхний элемент из стека вызовом рор(). Наверное, если бы разработчики использовали вместо рор какое-нибудь другое имя, недоразумений было бы меньше. Шаблон stack обладает простым интерфейсом - в сущности, все его функции уже были перечислены. Поскольку все обращения к элементам ограничиваются вершиной, стек не поддерживает итераторы для перебора элементов. Также отсутствуют изощренные формы инициализации, но при необходимости можно использовать средства того контейнера, на базе которого реализован стек. Допустим, имеется функция, рассчитанная на интерфейс стека, но в остальной части программы объекты должны храниться в виде списка. Следующая программа сохраняет каждую строку файла вместе с информацией о количестве начальных пробелов в этой строке (например, это может стать отправной точкой для переформатирования исходного кода программы). : C07:Stack2.cpp Преобразование списка в стек linclude <iostream> linclude <fstream> linclude <stack> linclude <list> linclude <string> linclude <cstddef> using namespace std: Ориентируется на стек: tempiate<class Stk> void stackOut(Stk& s. ostreamS os = cout) { whileCIs.emptyO) { OS s.topO \n : s.popO; class Line { string line; Без начальных пробелов size t 1 spaces: Количество начальных пробелов public: Line(string s) : line(s) { 1 spaces = line.find first not of( ): ifdspaces == string: :npos) 1 spaces = 0: line = 1ine.substr(1 spaces): friend ostream& operator (ostream& os, const Line& 1) { for(s1ze t 1 = 0: i < l.lspaces; i++) OS : return OS 1.line: Прочие функции... int mainO { ifstream in( Stack2.cpp ): list<Line> lines: Чтение файла и сохранение строк в списке: string s: while(getline(in, s)) lines.push front(s): Преобразование списка в стек для вывода: stack<Line. list<Line> > stk(lines); stackOut(stk): } /:- Функция, ориентированная на интерфейс stack, просто отправляет каждый объект top() в ostream, а затем удаляет его вызовом рор(). Класс Line определяет количество начальных пробелов и сохраняет содержимое строки без них. Оператор вывода в ostream снова вставляет начальные пробелы, чтобы строка выводилась в исходном виде, однако количество пробелов легко изменяется модификацией Ispaces (соответствующая функция здесь не приведена). В функции main() содержимое входного файла читается в list<Line>, после чего каждая строка в списке копируется в стек, выводимый в stackOut(). Перебор элементов стека невозможен; тем самым подчеркивается тот факт, что операции со стеком должны выполняться при создании стека. Функциональность стека можно имитировать при помощи вектора и его функций Ьаск(), push back() и рор Ьаск(), при этом становятся доступными все дополнительные возможности вектора. Программу Stackl.срр можно записать в следующем виде: : С07:Stacks.срр Эмуляция стека на базе вектора: измененная версия Stackl.срр #include <fstream> #include <iostream> #include <string> #include <vector>
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |