Итераторы вставки
Вот еще один фрагмент программы, в котором есть тонкая, но серьезная ошибка. Видите ли вы, в чем она заключается?
int ia[] = { 0, 1, 1, 2, 3, 5, 5, 8 }; vector< int > ivec( ia, ia+8 ), vres; // ... // поведение программы во время выполнения не определено |
unique_copy( ivec.begin(), ivec.end(), vres.begin() );
Проблема вызвана тем, что алгоритм unique_copy() использует присваивание для копирования значения каждого элемента из вектора ivec, но эта операция завершится неудачно, поскольку в vres не выделено место для хранения девяти целых чисел.
Можно было бы написать две версии алгоритма unique_copy(): одна присваивает элементы, а вторая вставляет их. Эта последняя версия должна, в таком случае, поддерживать вставку в начало, в конец или в произвольное место контейнера.
Альтернативный подход, принятый в стандартной библиотеке, заключается в определении трех адаптеров, которые возвращают специальные итераторы вставки:
· back_inserter()
вызывает определенную для контейнера операцию вставки push_back()
вместо оператора присваивания. Аргументом back_inserter() является сам контейнер. Например, вызов unique_copy()
можно исправить, написав:
// правильно: теперь unique_copy() вставляет элементы с помощью // vres.push_back()... unique_copy( ivec.begin(), ivec.end(), |
back_inserter( vres ) );
· front_inserter()
вызывает определенную для контейнера операцию вставки push_front()
вместо оператора присваивания. Аргументом front_inserter()
тоже является сам контейнер. Заметьте, однако, что класс vector не поддерживает push_front(), так что использовать такой адаптер для вектора нельзя:
// увы, ошибка: // класс vector не поддерживает операцию push_front() // следует использовать контейнеры deque или list unique_copy( ivec.begin(), ivec.end(), |
front_inserter( vres ) );
· inserter()
вызывает определенную для контейнера операцию вставки insert()
вместо оператора присваивания. inserter() принимает два аргумента: сам контейнер и итератор, указывающий позицию, с которой должна начаться вставка:
unique_copy( ivec.begin(), ivec.end(), |
· Итератор, указывающий на позицию начала вставки, сдвигается вперед после каждой вставки, так что элементы располагаются в нужном порядке, как если бы мы написали:
vector< int >::iterator iter = vres.begin(), iter2 = ivec.begin(); for ( ; iter2 != ivec.end() ++ iter, ++iter2 ) |