Программирование >>  Разработка устойчивых систем 

1 ... 105 106 107 [ 108 ] 109 110 111 ... 196


В целях эффективности некоторые алгоритмы предоставляют разные реализации для разных типов итераторов. Информацию о типе итератора они получают из итераторного тега, определяемого итератором. С некоторыми классами итера-торных тегов мы познакомимся позже, когда мы займемся определением пользовательских итераторов.

Стандартные итераторы

в 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



1 ... 105 106 107 [ 108 ] 109 110 111 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика