Итераторы (окончание)

   
На этом шаге мы рассмотрим небольшой пример использования итераторов.

   
Следующий пример демонстрирует применение итераторов. В нем выводятся значения всех элементов списка (усовершенствованная
версия примера со списками, приведенного на 87 шаге).

//---------------------------------------------------------------------------

#include <vcl.h>
#include <iostream>
#include <list>
#include <conio.h> //необходимо для getch()
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;
std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}

int main(int argc, char* argv[])
{
  list<char> coll; // Список с символьными элементами
  // Присоединение элементов от 'a' по 'z'
  for (char c='a'; c<='z'; ++c) {
    coll.push_back(c);
  }
  cout << ToRus("Элементы списка: ");
  // Вывод содержимого списка:
  // перебор всех элементов.
  list<char>::const_iterator pos; 
  for (pos = coll.begin(); pos != coll.end(); ++pos) { 
    cout << *pos << ' ';
  }
  cout << endl;

  getch();
  return 0;
}
//---------------------------------------------------------------------------

Текст этого примера можно взять здесь.

   
После того как список создан и заполнен символами от "а" до "z", все элементы выводятся в цикле for:

  list<char>::const_iterator pos; 
  for (pos = coll.begin(); pos != coll.end(); ++pos) { 
    cout << *pos << ' ';
  }

   
Итератор pos объявляется непосредственно перед началом цикла. В объявлении выбирается тип итератора для обращения к
элементам контейнерного класса без возможности модификации:

  list<char>::const_iterator pos; 

   
В каждом контейнере определены два типа итераторов:

  • контейнер::iterator - используется для перебора элементов в режиме чтения/записи;
  • контейнер::const_iterator - используется для перебора элементов в режиме чтения.

   
Скажем, в классе list эти определения выглядят примерно так:

namespace std {
  template <class T> 
  class list { 
    public:
      typedef ... iterator; 
      typedef ... const_iterator;
      .    .    .    .
  }
}

   
Конкретный тип итераторов iterator и const_iterator зависит от реализации. В теле цикла for итератор
pos инициализируется позицией первого элемента:

  pos = coll.begin();

   
Цикл продолжается до тех пор, пока pos не выйдет за пределы интервала контейнерных элементов:

  pos != coll.end();

   
В этом условии итератор pos сравнивается с конечным итератором. Оператор ++pos в заголовке цикла перемещает
итератор pos к следующему элементу.

   
В итоге итератор pos перебирает все элементы, начиная с первого, пока не дойдет до конца (рисунок 1).


Рис.1. Итератор pos при переборе элементов списка

   
Если контейнер не содержит ни одного элемента, тело цикла не выполняется, потому что значение coll.begin() будет равным
значению coll.end().

   
В теле цикла текущий элемент представляется выражением *pos. Модификация текущего элемента невозможна, потому что
итератор был объявлен с типом const_iterator, а значит, с точки зрения итератора элементы являются константными. Но если
объявить неконстантный итератор для перебора неконстантных элементов, значения можно будет изменить. Пример:

// Приведение всех символов в списке к верхнему регистру 
list<char>::iterator pos;
for (pos = coll.begin(); pos != coll.end(); ++pos) {
  *pos = toupper(*pos); 
}

   
Обратите внимание на использование префиксной версии оператора ++. Возможно, в этом случае она работает эффективнее
постфиксной версии, которая создает временный объект для возвращения старой позиции итератора. Из-за этого в общем случае
рекомендуется использовать ++pos вместо pos++, а следующее решение нежелательно:

// Приведение всех символов в списке к верхнему регистру 
list<char>::iterator pos;
for (pos = coll.begin(); pos != coll.end(); pos++) {
  .    .    .    .  // Работает, но медленнее
}

   
По этой причине можно рекомендовать ограничиваться префиксными формами операторов увеличения и уменьшения.

   
Со следующего шага мы приведем примеры использования ассоциативных контейнеров.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий