|
Программирование >> Разработка устойчивых систем
Такое решение работает только в тех реализациях вектора, которые в качестве типа итератора используют указатель (Т*), например, в STLPort. operator (ostream& os. const Z& z) { return OS z.i: int mainO { ostream iterator<Z> out(cout. ): vector<Z> vz: for(int i = 0; i < 10: i++) vz.push back(Z(i)): copy (vz. begi n(), vz.endO, out): cout endl: apply(vz. &Z::g): copy(vz.begin(). vz.endO. out): } III:- В данном случае мы не можем использовать операторную функцию operator->, потому что команда будет иметь вид (it->*f)(): Компилятор попытается использовать операторную функцию operator->*, не поддерживаемую классами итераторов. Как было показано в предыдущей главе, для выполнения некоторой операции с каждым элементом контейнера гораздо удобнее воспользоваться алгоритмом for each() или transform(). Итераторы в обратимых контейнерах Контейнеры могут обладать свойством обратимости; это означает, что они позволяют создавать как итераторы, перемещающиеся от начала к концу, так и итераторы, перемещающиеся от конца к началу. Все стандартные контейнеры поддерживают двусторонний перебор. У обратимых контейнеров определены функции rbegin() (для получения итератора reversejterator, установленного на последний элемент) и rend() (для получения итератора reversejterator, установленного в позицию перед началом контейнера ). Если контейнер объявлен константным, функции rbeginQ и rend() возвращают константные итераторы. В следующем примере используется класс vector, но он также работает со всеми контейнерами, поддерживающими итераторы: : С07:Reversible.срр Использование обратимых контейнеров #include <fstream> #include <iostream> #include <string> #i nclude <vector> #include ../require.h using namespace std: int mainO { ifstream in( Reversible.cpp ): assure(in. Reversible.cpp ): string line: vector<string> lines: while(getline(in. line)) lines.push back(line): for(vector<string>::reverse iterator r = lines.rbeginO: r != lines.rendO: r++) cout *r endl: } III:- Синтаксис перебора в обратном направлении ничем не отличается от синтаксиса прямого перебора с применением обычных итераторов. Категории итераторов Итераторы стандартной библиотеки С++ делятся на категории, описывающие их возможности. Обычно перечисление этих категорий начинается с простейших. Итераторы ввода - только чтение, один проход Итераторы ввода существуют всего в двух стандартных реализациях: istreamjterator и istreambuf Jterator для чтения из потока istream. Как нетрудно догадаться, итератор ввода может быть разыменован только один раз для каждого элемента, подобно тому, как каждая часть входного потока может быть прочитана только один раз. Итераторы ввода перемещаются только в прямом направлении (от начала к концу); конечный итератор определяется специальным конструктором. Короче говоря, итератор ввода поддерживает разыменование (только один раз для каждого значения) и перемещение вперед. Итераторы вывода - только запись, один проход Итератор вывода похож на итератор ввода, но он предназначен для записи, а не для чтения. Итераторы вывода существуют в стандартных реализациях ostreamjterator и ostreambuf Jterator для записи в поток ostream, а также реже используемой реализации raw storage Jterator. Они также могут разыменовываться только один раз для каждого записанного значения и поддерживают перемещение только от начала к концу контейнера. Для итераторов вывода не существует понятия конечного значения , после которого дальнейшее перемещение невозможно. Итак, итераторы вывода поддерживают разыменование (только один раз для каждого значения) и перемещение вперед. Прямые итераторы - множественные операции чтения-записи Прямой итератор объединяет всю функциональность итераторов ввода и вывода, а также возможность многократного разыменования, что позволяет многократно читать и записывать элементы. Как подсказывает название, перемещение возможно только в прямом направлении. В стандартной библиотеке не существует стандартных итераторов, которые бы относились к этой категории. Двусторонние итераторы - оператор Двусторонний итератор обладает всеми возможностями прямого итератора, а также может перемещаться назад на одну позицию оператором ~. Итераторы, возвращаемые контейнером list, являются двусторонними. Итераторы произвольного доступа - аналоги указателей Наконец, итераторы произвольного доступа обладают всеми возможностями двусторонних итераторов, а также всеми основными возможностями указателей (указатель является частным случаем итератора произвольного доступа), кроме одной: у них отсутствует нуль-итератор , аналог нуль-указателя. С итераторами произвольного доступа выполняются такие же операции, как с указателями: индексация оператором [ ], прибавление целочисленного смещения (положительного или отрицательного) для перехода сразу на несколько позиций, сравнение итераторов операторами отнощения. О важности классификации Но стоит ли задумываться о том, к какой категории относится тот или иной итератор? При выполнении простейших операций с контейнерами (например, при ручном кодировании всех операций, выполняемых с объектами контейнеров) категория итератора обычно несущественна - итератор либо работает, либо не работает. Однако в некоторых ситуациях категории итераторов действительно важны. При использовании нетривиальных разновидностей итераторов (см. далее) и при создании собственных итераторов. При использовании алгоритмов STL (эта тема рассматривалась в предыдущей главе). Каждый алгоритм предъявляет определенные требования к своим итераторам. Информация о категории итератора играет еще более важную роль при создании пользовательских шаблонов алгоритмов, поскольку категория итератора, обязательная для вашего алгоритма, определяет его универсальность. Если алгоритм обходится самой примитивной категорией итераторов (ввода или вывода), он будет работать с любыми итераторами (примером может служить алгоритм сору()). Категория итератора определяется иерархией специальных классов - итера-торных тегов. Имена классов соответствуют категориям итераторов, а иерархия наследования отражает логические связи между ними: Итератор ввода struct input iterator tag {}: Итератор вывода struct output iterator tag {}; Прямой итератор struct forward iterator tag: public input iterator tag {}: Двусторонний итератор struct bidirectional iterator tag : public forward iterator tag {}: Итератор произвольного доступа struct randoni accessJterator tag : public bidirectional iterator tag {}; Класс forwardJterator tag наследует только от inputJterator tag, но не от outputJterator tag, потому что алгоритмы, использующие прямые итераторы, должны поддерживать концепцию конечных итераторов, а алгоритмы с итераторами вывода предполагают, что итератор всегда можно разыменовать оператором *. По этой причине очень важно, чтобы конечный итератор никогда не передавался алгоритму, получающему итератор вывода.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |