Читаем Программирование. Принципы и практика использования C++ Исправленное издание полностью

Итератор — это аналог указателя, в котором реализованы операции косвенного доступа (например, оператор * для разыменования) и перехода к новому элементу (например, оператор ++ для перехода к следующему элементу). Последовательность элементов определяется парой итераторов, задающих полуоткрытый диапазон [begin:end].

Иначе говоря, итератор begin указывает на первый элемент последовательности, а итератор end — на элемент, следующий за последним элементом последовательности. Никогда не считывайте и не записывайте значение *end. Для пустой последовательности всегда выполняется условие begin==end. Другими словами, для любого итератора p последовательность [p:p] является пустой.

Для того чтобы считать последовательность, алгоритм обычно получает пару итераторов (b, e) и перемещается по элементам с помощью оператора ++, пока не достигнет конца.

while (b!=e) { // используйте !=, а не <

               // какие-то операции

  ++b;         // переходим к последнему элементу

}

Алгоритмы, выполняющие поиск элемента в последовательности, в случае неудачи обычно возвращают итератор, установленный на конец последовательности. Рассмотрим пример.

p = find(v.begin,v.end,x); // ищем x в последовательности v

if (p!=v.end) {

      // x найден в ячейке p

}

else {

      // x не найден в диапазоне [v.begin:v.end)

}

См. раздел 20.3.

Алгоритмы, записывающие элементы последовательности, часто получают только итератор, установленный на ее первый элемент. В данном случае программист должен сам предотвратить выход за пределы этой последовательности. Рассмотрим пример.

template void f(Iter p, int n)

{

  while (n>0) *p++ = ––n;

  vector v(10);

  f(v.begin,v.size); // OK

  f(v.begin,1000);     // большая проблема

Некоторые реализации стандартной библиотеки проверяют выход за пределы допустимого диапазона, т.е. генерируют исключение, при последнем вызове функции f, но этот код нельзя считать переносимым; многие реализации эту проверку не проводят.

Перечислим операции над итераторами.

Обратите внимание на то, что не каждый вид итераторов (раздел Б.3.2) поддерживает все операции над итераторами.

<p id="AutBody_Root645"><strong>Б.3.2. Категории итераторов</strong></p>

В стандартной библиотеке предусмотрены пять видов итераторов.

С логической точки зрения итераторы образуют иерархию (см. раздел 20.10).

Поскольку категории итераторов не являются классами, эту иерархию нельзя считать иерархией классов, реализованной с помощью наследования. Если вам требуется выполнить над итераторами нетривиальное действие, поищите класс iterator_traits в профессиональном справочнике.

Каждый контейнер имеет собственные итераторы конкретной категории:

vector — итераторы произвольного доступа;

list — двунаправленные итераторы;

deque — итераторы произвольного доступа;

bitset — итераторов нет;

set — двунаправленные итераторы;

multiset — двунаправленные итераторы;

map — двунаправленные итераторы;

multimap — двунаправленные итераторы;

unordered_set — однонаправленные итераторы;

unordered_multiset — однонаправленные итераторы;

unordered_map — однонаправленные итераторы;

unordered_multimap — однонаправленные итераторы.

<p id="AutBody_Root646"><strong>Б.4. Контейнеры</strong></p>

Контейнер содержит последовательность элементов. Элементы этой последовательности имеют тип value_type. Наиболее полезными контейнерами являются следующие.

Эти контейнеры определены в классах , и др. (см. раздел Б.1.1). Последовательные контейнеры занимают непрерывную область памяти или представляют собой связанные списки, содержащие элементы соответствующего типа value_type (выше мы обозначали его буквой T). Ассоциативные контейнеры представляют собой связанные структуры (деревья) с узлами соответствующего типа value_type (выше мы обозначали его как pair(K,V)). Последовательность элементов в контейнерах set, map или multimap упорядочена по ключу (K). Последовательность в контейнерах, название которых начинается со слова unordered, не имеет гарантированного порядка. Контейнер multimap отличается от контейнера map тем, что в первом случае значение ключа может повторяться много раз. Адаптеры контейнеров — это контейнеры со специальными операциями, созданные из других контейнеров.

Если сомневаетесь, используйте класс vector. Если у вас нет весомой причины использовать другой контейнер, используйте класс vector.

Перейти на страницу:

Похожие книги

97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

Успешная карьера архитектора программного обеспечения требует хорошего владения как технической, так и деловой сторонами вопросов, связанных с проектированием архитектуры. В этой необычной книге ведущие архитекторы ПО со всего света обсуждают важные принципы разработки, выходящие далеко за пределы чисто технических вопросов.?Архитектор ПО выполняет роль посредника между командой разработчиков и бизнес-руководством компании, поэтому чтобы добиться успеха в этой профессии, необходимо не только овладеть различными технологиями, но и обеспечить работу над проектом в соответствии с бизнес-целями. В книге более 50 архитекторов рассказывают о том, что считают самым важным в своей работе, дают советы, как организовать общение с другими участниками проекта, как снизить сложность архитектуры, как оказывать поддержку разработчикам. Они щедро делятся множеством полезных идей и приемов, которые вынесли из своего многолетнего опыта. Авторы надеются, что книга станет источником вдохновения и руководством к действию для многих профессиональных программистов.

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT