Итераторные адаптеры. Итераторы вставки

   
На этом шаге мы рассмотрим разновидности итераторов вставки.

   
Итераторы являются чистыми абстракциями; иначе говоря, любой объект, который ведет себя как итератор, является итератором. По
этой причине вы можете написать класс, который обладает интерфейсом итератора, но делает нечто совершенно иное. Стандартная
библиотека C++ содержит несколько готовых специализированных итераторов, называемых итераторными адаптерами.
Не стоит полагать, что итераторные адаптеры являются обычными вспомогательными классами; они наделяют саму концепцию
итераторов рядом новых возможностей.

   
Далее представлены три разновидности итераторных адаптеров:

  • итераторы вставки;
  • потоковые итераторы;
  • обратные итераторы.

Итераторы вставки

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

   
Поведение итераторов вставки слегка переопределено.

  • Если присвоить значение элементу, ассоциированному с итератором, это значение вставляется в коллекцию, с которой связан
    данный итератор. Три разновидности итераторов вставки позволяют вставлять элементы в разных местах - в начале, в конце или
    в заданной позиции.
  • Операция перехода вперед не производит никаких действий.

   
Рассмотрим следующий пример:

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

#include <vcl.h>
#include <iostream>
#include <vector>
#include <list>
#include <deque> 
#include <set> 
#include <algorithm>
#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<int> coll1;
  list<int>::iterator pos1;

  // Вставка элементов со значениями от 1 до 9
  for (int i=1; i<=9; ++i) {
    coll1.push_back(i);
  }

  // Вывод элементов списка
  cout << ToRus("Элементы списка: ");
  for (pos1 = coll1.begin(); pos1 != coll1.end(); ++pos1) {
    cout << *pos1 << ' ';
  }
  cout << endl;

  // Копирование элементов из coll1 в coll2 с присоединением
  vector<int> coll2;
  vector<int>::iterator pos2;

  copy (coll1.begin(), coll1.end(), // Источник
    back_inserter(coll2));  // Приемник

  // Вывод элементов вектора
  cout << ToRus("Элементы вектора: ");
  for (pos2 = coll2.begin(); pos2 != coll2.end(); ++pos2) {
    cout << *pos2 << ' ';
  }
  cout << endl;

  // Изменение размера приемного интервала,
  // чтобы он были достаточен для работы алгоритма
  // с перезаписью.
  coll2.resize (coll1.size());

  // Копирование элементов из первой коллекции во вторую
  // - перезапись существующих элементов в приемном интервале
  copy (coll1.begin(),coll1.end(),   // Источник
    coll2.begin()); // Приемник

  // Копирование элементов coll1 в соll3 со вставкой в начало
  // - порядок следования элементов заменяется на противоположный
  deque<int> coll3;
  deque<int>::iterator pos3;
  copy (coll1.begin(),coll1.end(),   // Источник
    front_inserter(coll3)); // Приемник

  // Вывод элементов дека
  cout << ToRus("Элементы дека: ");
  for (pos3 = coll3.begin(); pos3 != coll3.end(); ++pos3) {
    cout << *pos3 << ' ';
  }
  cout << endl;

  // Копирование элементов coll1 в coll4
  // - единственный итератор вставки, работающий
  // с ассоциативными контейнерами
  set<int> coll4;
  set<int>::iterator pos4;
  copy (coll1.begin(), coll1.end(),  // Источник
    inserter(coll4,coll4.begin()));  // Приемник

  // Вывод элементов множества
  cout << ToRus("Элементы множества: ");
  for (pos4 = coll4.begin(); pos4 != coll4.end(); ++pos4) {
    cout << *pos4 << ' ';
  }
  cout << endl;

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

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

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


Рис.1. Результат работы приложения

   
В этом примере встречаются все три разновидности итераторов вставки.

  • Конечные итераторы вставки. Элементы вставляются в конец контейнера (то есть присоединяются) вызовом
    push_back(). Например, следующая команда присоединяет все элементы coll1 к coll2:

      copy (coll1.begin(), coll1.end(),   // Источник
        back_inserter(coll2));  // Приемник
    

       
    Разумеется, конечные итераторы вставки могут использоваться только с контейнерами, поддерживающими функцию push_back().
    В стандартной библиотеке C++ такими контейнерами являются векторы, деки и списки.

  • Начальные итераторы вставки. Элементы вставляются в начало контейнера вызовом push_front().
    Например, следующая команда вставляет все элементы coll1 в coll3:

      copy (coll1.begin(), coll1.end(),   // Источник
        front_inserter(coll3)); // Приемник
    

       
    Помните, что данная разновидность вставки меняет порядок следования элементов. Если вставить в начало значение1,
    а затем значение2, то 1 окажется после 2.

       
    Начальные итераторы вставки могут использоваться только с контейнерами, поддерживающими функцию push_front(). В
    стандартной библиотеке С++ такими контейнерами являются деки и списки.

  • Унифицированные итераторы вставки. Унифицированный итератор вставки, также называемый просто
    итератором вставки, вставляет элементы непосредственно перед позицией, переданной во втором аргументе при инициализации.
    Он вызывает функцию insert() и передает ей значение и позицию нового элемента. Вспомните, что все контейнеры, определенные
    в STL, поддерживают функцию insert(); это единственный итератор вставки в ассоциативных контейнерах.

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

   
В таблице 1 перечислены разновидности итераторов вставки.

Таблица 1. Стандартные итераторы вставки

Выражение Разновидность итератора
back_inserter (контейнер) Элементы присоединяются с конца в прежнем порядке с использованием функции push_back()
front_inserter (контейнер) Элементы вставляются в начало в обратном порядке с использованием функции push_front()
inserter (контейнер, позиция) Элементы вставляются в заданной позиции в прежнем порядке с использованием функции insert()

   
На следующем шаге мы рассмотрим потоковые итераторы.



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

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