На этом шаге мы рассмотрим разновидности итераторов вставки.
Итераторы являются чистыми абстракциями; иначе говоря, любой объект, который ведет себя как итератор, является итератором. По этой причине вы можете написать класс, который обладает интерфейсом итератора, но делает нечто совершенно иное. Стандартная библиотека 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. Результат работы приложения
В этом примере встречаются все три разновидности итераторов вставки.
copy (coll1.begin(), coll1.end(), // Источник back_inserter(coll2)); // Приемник
Разумеется, конечные итераторы вставки могут использоваться только с контейнерами, поддерживающими функцию push_back(). В стандартной библиотеке C++ такими контейнерами являются векторы, деки и списки.
copy (coll1.begin(), coll1.end(), // Источник front_inserter(coll3)); // Приемник
Помните, что данная разновидность вставки меняет порядок следования элементов. Если вставить в начало значение1, а затем значение2, то 1 окажется после 2.
Начальные итераторы вставки могут использоваться только с контейнерами, поддерживающими функцию push_front(). В стандартной библиотеке С++ такими контейнерами являются деки и списки.
Однако ранее говорилось, что задать позицию нового элемента в ассоциативном контейнере невозможно, потому что позиции элементов зависят от их значений? Все просто: в ассоциативных контейнерах переданная позиция интерпретируется как рекомендация для начала поиска нужной позиции. Однако если переданная позиция окажется неверной, на выполнение операции может понадобиться больше времени, чем вообще без рекомендации.
В таблице 1 перечислены разновидности итераторов вставки.
Выражение | Разновидность итератора |
---|---|
back_inserter (контейнер) | Элементы присоединяются с конца в прежнем порядке с использованием функции push_back() |
front_inserter (контейнер) | Элементы вставляются в начало в обратном порядке с использованием функции push_front() |
inserter (контейнер, позиция) | Элементы вставляются в заданной позиции в прежнем порядке с использованием функции insert() |
На следующем шаге мы рассмотрим потоковые итераторы.