|
Программирование >> Разработка устойчивых систем
В целях эффективности некоторые алгоритмы предоставляют разные реализации для разных типов итераторов. Информацию о типе итератора они получают из итераторного тега, определяемого итератором. С некоторыми классами итера-торных тегов мы познакомимся позже, когда мы займемся определением пользовательских итераторов. Стандартные итераторы в STL входит набор заранее определенных итераторов. В частности, мы уже встречались с объектами reverse Jterator, которые создаются функциями rbegin() и rend() всех основных контейнерных классов. Итераторы вставки необходимы из-за того, что некоторые алгоритмы STL (например, соруО) заносят объекты в приемный контейнер оператором присваивания =. Проблемы возникают, если алгоритм используется для заполнения контейнера (вместо замены объектов, уже присутствующих в контейнере), то есть когда память для элементов еще не выделена. Итераторы вставки изменяют реализацию оператора = так, чтобы вместо присваивания вызывалась функция push или insert соответствующего контейнера. Тем самым обеспечивается выделение памяти для новых элементов. Конструкторы basicjnsertjterator и frontjnsertjterator получают при вызове объект одного из базовых классов последовательных контейнеров (vector, deque или list) и создают итератор, который для присваивания вызывает соответственно функции push back() или push Jront(). Вспомогательные функции backJnserterO и frontJnserter() создают те же объекты итераторов вставки с конца и с начала контейнера, но вводятся быстрее. Поскольку функция push back() поддерживается всеми базовыми последовательными контейнерами, вероятно, вы будете довольно часто использовать в своей работе функцию backjnserter(). Итератор insertjterator вставляет элементы в середину последовательности. Он тоже переопределяет смысл оператора =, но вместо функций категории push он автоматически вызывает функцию insert(). При вызове этой функции класса должен передаваться итератор, установленный в позицию перед позицией вставки, поэтому у объекта insertjterator должны быть два аргумента: контейнер и итератор. Вспомогательная функция inserter() создает этот же объект. Следующий пример демонстрирует применение различных категорий итераторов. : С07:Inserters.срр Различные типы итераторов вставки linclude <iostream> linclude <vector> linclude <deque> linclude <list> linclude <iterator> using namespace std: int a[] { 1. 3. 5. 7. 11. 13. 17. 19. 23 }: tempiate<class Cont> void frontInsertion(Cont& ci) { copy(a, a + sizeof(a)/sizeof(Cont::value type), frontjnserter(ci)): copy(ci .beginO. ci.endO. ostream iterator<typename Cont::value type>( cout, )): cout endl: tempiate<class Cont> void backInsertion(Cont& ci) { copyCa. a + sizeof(a)/sizeof(Cont::value type). back inserter(ci)); copy(ci-beginO. ci.endO. ostream iterator<typename Cont::value type>( cout, )): cout endl: tempiate<class Cont> void midInsertion(Cont& ci) { typename Cont::iterator it = ci.beginO: ++it: ++it: ++it: copyCa. a + sizeof(a)/(sizeof(Cont::value type) * 2), inserter(ci. it)): copyCci .beginO, ci.endO. ostream iterator<typename Cont::value type>( cout. )): cout endl: int mainO { deque<int> di: list<int> li: vector<int> vi: frontJnserterO не может использоваться с вектором frontInsertion(di): frontlnsertion(li): di .clearO: li.clearO: backlnsertion(vi); backInsertion(di) backlnsertion(li) midInsertion(vi) midlnsertionCdi) midlnsertiondi) } III- Так как шаблон vector не поддерживает функцию push front(), он не может создать объект frontjnsertjterator. С другой стороны, вектор поддерживает два других типа вставки (хотя как будет показано позднее, операция insert() для векторов работает неэффективно). Обратите внимание на использование вложенного типа Cont::value type вместо жесткого кодирования типа int. Снова о потоковых итераторах Потоковые итераторы ostreamjterator (итератор вывода) и istreamjterator (итератор ввода) } же упоминались при рассмотрении алгоритма сору() в главе 6. Не забывайте, что для потоков вывода не определено понятие конца потока , поскольку в них всегда можно вывести новые элементы. Однако поток ввода рано или поздно завершается (например, при достижении конца файла), и это состояние нужно как-то представить. У объектов istreamjterator имеются два конструктора: Точнее говоря, эти итераторы создавались для абстрагирования потоков ввода-вывода от фацетов локальных контекстов, чтобы фацеты могли работать с любыми последовательностями символов, не только с потоками. Локальные контексты обеспечивают удобное форматирование потоков ввода-вывода по национальным стандартам (например, представление денежных величин). Для остальных типов аргументов необходимо предоставить специализацию шаблона char traits. первый получает istream и создает итератор, через который можно читать данные, а второй (конструктор по умолчанию) создает объект конечного итератора. В следующей программе этот объект называется end: : C07:StreamIt.cpp Итераторы потоков ввода и вывода #include <fstream> #include <1ostream> #inc1ude <1terator> #1nclude <string> linclude <vector> #include ../require.h using namespace std; int mainO { ifstream in( StreamIt.cpp ); assure(in. Streamlt.cpp ); istreamjterator<string> begin(in). end; ostreamJterator<string> out(cout. \n ); vector<string> vs; copy(begin. end. backjnserter(vs)); copy(vs.beginO. vs.endO. out); *out++ = vs[0]; *out++ = Thats all. folks! ; } /:- Когда в потоке in кончаются входные данные (в данном случае - при достижении конца файла), копирование заверщается. Так как итератор out относится к классу output iterator<string>, разыменованному итератору можно просто присвоить любой объект string оператором =. Присвоенная строка помещается в выходной поток, как в двух присваиваниях out в нащем примере. При определении out во втором аргументе передается символ перевода строки, поэтому команда присваивания также включает в поток перевод строки. Хотя создать объекты istream iterator<char> и ostream iterator<char> возможно, фактически они будут выполнять синтаксический разбор входных данных. В частности, произойдет автоматическое исключение пропусков (пробелов, символов табуляции и перевода строки), а это нежелательно, если вы хотите работать с точным представлением потока istream. Вместо них следует использовать итераторы istreambufjterator и ostreambufjterator, спроектированные специально для работы с отдельными символами. Хотя они реализованы в виде шаблонов, предполагается, что в аргументах передаются только типы char и wchar tl В следующем примере поведение потоковых итераторов сравнивается с итераторами streambuf: : С07:StreambufIterator.срр istreambuf iterator и ostreambuf iterator #include <algorithm> #include <fstream> linclude <iostream> linclude <iterator> #include ../require.h
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |