Программирование >>  Операторы преобразования типа 

1 ... 79 80 81 [ 82 ] 83 84 85 ... 239


cout endl;

/* Вывод всех элементов

* - ВНИМАНИЕ: применение оператора [] вместо оператора * */

for (int i-0: 1<со11,sl2e(): ++i) { cout coll.begin()[1] ;

cout endl:

/* Вывод каждого второго эпемента

* - ВНИМАНИЕ: применение оператора += */

for (pos = coll.beginO: pos < coll .endC)-l: pos += 2) { cout *pos :

cout endl;

Результат выполнения программы выглядит так:

number/distance: 13 -3-2-10123456789 -3-2-10123456789 -3-11357

Этот пример не работает со списками, множествами и отображениями, потому что все операции с пометкой ВНИМАНИЕ; поддерживаются только для итераторов произвольного доступа. В частности, помните, что оператор < может использоваться в критерии завершения цикла только для итераторов произвольного доступа.

Следующее выражение в последнем цикле требует, чтобы коллекция coll содержала минимум один элемент:

pos < coll.endC)-l

Если коллекция пуста, то coll.end()-l будет ссылаться на позицию перед coll.begin(). Сравнение останется работоспособным, но, формально говоря, перемещение итератора в позицию перед началом коллекции приводит к непредсказуемым последствиям. То же самое происходит при выходе за пределы конечрюго итератора end() при выполнении выражения ро5-ь=2. Таким образом, следующая формулировка последнего цикла очень опасна, потому что при четном количестве элементов в коллекции она приводит к непредсказуемым последствиям (рис. 7.2):

for (pos = coll.beginO: pos < coll.endO; pos += 2) { cout *pos ;




Рис. 7.2. Категории итераторов

Проблема увеличения и уменьшения итераторов в векторах

при применении в векторах операторов увеличения и уменьптения к тггерато-рам возникает странная проблема. Вообще говоря, увеличение и уменьшение временных итераторов разрешено, но для векторов и строк оно обычно запрещено. Рассмотрим следующий пример:

std::vector<1nt> coll:

Сортировка, начиная со второго элемента - НЕПЕРЕНОСИМАЯ версия 1f (coll.SizeO > 1) {

sort(++coll .beg1n(). coll.endO);

Обычно КОМПНЛЯЩ1Я строки с вызовом sort() завершается неудачей, но если заменить вектор деком, компиляция пройдет нормально. Иногда программа компилируется даже для векторов - это зависит от реализации класса vector.

Дело в том, что векторные итераторы обычно реализуются в виде обьшных указателей. Для всех базовых тттов данных, в том числе и для указателей, модификация временных значений запрещена. С другой сторога, для структур и классов она разрегиена. Следовательно, если ттгератор реализован в виде обычного указателя, программа ие компилируется; если итератор реализован в виде класса, компиляция проходит успешно. Для деков, списков, множеств и отображений такой проблемы не существует, поскольку в них итераторы в пршщипе пе реализуются в виде обычных указателей, но для векторов все зависит от реализации. В большинстве реализаций задействованы обычные указатели. Но, например, в безопасной версии STL итераторы реализованы в виде классов. Чтобы приведенный выше фрагмент был переносимым, достаточно определить промежуточный объект:

std::vector<1nt> coll;

Сортировка, начиная со второго элемента - ПЕРЕНОСИМАЯ версия if (coll .SizeO > 1) {



std: :vector<lnt>:: iterator beg = coll.beginO: sort C++C0II .beg, coll.endO):

Проблема не так серьезна, как кажется на первый взгляд. Она обнаруживается на стадии компиляции и поэтому не приводит к непредсказуемым последствиям. С другой стороны, проблема достаточно нетривиальна, и на ее выявление иногда уходит немало времени. Кроме того, она относится не только к векторам, но и к строкам. Строковые итераторы тоже обычно реализуются в виде обычных указателей на символы, хотя это и не обязательно.

Вспомогательные функции итераторов

Стандартная библиотека С++ содержит три вспомогательные функции для работы с итераторами: advance(), distance() и iter swap(). Первые две функции предоставляют для любого итератора возможности, которыми обычно обладают только итераторы произвольного доступа: перемещение итератора сразу на несколько элементов вперед (или назад) и вычисление разности между итераторами. Третья вспомогательная функция меняет местами элементы, на которые ссылаются два итератора.

Перебор итераторов функцией advance

Функция advanceO перемещает итератор, передаваемый ей в качестве аргумента. При этом смещение может производиться в прямом (илн обратном) направлении сразу на несколько элементов:

#include <1terator>

void advance (InputIterator& pos. Dist n)

О Перемещает итератор ввода p05 на п элементов вперед (или назад).

О Для двунаправленных итераторов и итераторов произвольного доступа значение п может быть отррщательным (перемещение в обратном направлении).

О Dist - тин шаблона. Обычно является целым типом, поскольку для него вызываются такие операции, как <, ++, - и сравнение с 0.

О Обратите внимание, что функция advance() не проверяет выход за пределы end() (и не может проверять, поскольку в общем случае итератор не располагает информацией о контейнере, с которым он работает). Таким образом, вызов этой функции может привести к непредсказуемым последствиям из-за вызова оператора ++ в конце последовательности.

Благодаря разным трактовкам итераторов (см. с. 288) функция всегда использует оптимальную реализацию в зависимости от категории итератора. Для итераторов произвольного доступа она просто вызывает pos+=n. Следовательно, для таких итераторов функция advance() имеет постоянную сложность. Для остальных итераторов используется и-кратный вызов pos (или -pos, если значение п отрицательно). Таким образом, для всех остальных категорий итераторов функция advanceO выполняется с лттейной сложностью.



1 ... 79 80 81 [ 82 ] 83 84 85 ... 239

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