Стандартная библиотека C++<iterator>
В стандартной библиотеке C++,<iterator>Заголовочный файл предоставляет набор инструментов для обхода элементов в контейнерах. Итераторы — одна из основных концепций стандартной библиотеки шаблонов C++ (STL), позволяющая программистам единообразно получать доступ к элементам в контейнерах, не беспокоясь о конкретных деталях реализации контейнера.
Итератор — это объект, предоставляющий способ обхода элементов в контейнере. Итератор можно рассматривать как указатель на элемент в контейнере, но он более гибкий и мощный, чем указатель. Итераторы можно использовать для доступа к элементам в контейнере и их изменения, а также совместно с алгоритмами STL.
Итераторы в основном делятся на следующие категории:
- Итератор ввода: может выполнять только одиночные операции чтения, не может выполнять операции записи.
- Итератор вывода: может выполнять только одиночные операции записи, не может выполнять операции чтения.
- Однонаправленный итератор: может выполнять операции чтения и записи, а также перемещаться вперёд.
- Двунаправленный итератор: в дополнение ко всем операциям однонаправленного итератора он также может перемещаться назад.
- Итератор произвольного доступа: в дополнение ко всем операциям двунаправленного итератора он также может выполнять произвольный доступ, например доступ к элементам по индексу.
Часто используемые функции (ключевой момент)
| Функция | Функция | Пример | Описание |
|---|---|---|---|
std::advance(it, n) |
Переместить итератор вперёд на n шагов | advance(it, 2); |
Изменит исходный итератор |
std::distance(a, b) |
Вычислить расстояние между двумя итераторами | distance(v.begin(), v.end()); |
Возвращает количество элементов |
std::next(it, n) |
Вернуть новый итератор, продвинутый на n шагов | auto it2 = next(it, 2); |
Рекомендуется, не изменяет исходное значение |
std::prev(it, n) |
Вернуть новый итератор, сдвинутый назад на n шагов | auto it2 = prev(it, 1); |
Поддерживается начиная с C++11 |
Адаптеры итераторов (очень важно)
Адаптеры итераторов могут изменять поведение итераторов, чтобы адаптировать их к различным сценариям использования.
| Adapter | Функция | Пример |
|---|---|---|
std::back_inserter |
Вставка в конец (вызов push_back) | back_inserter(vec) |
std::front_inserter |
Вставка в начало (вызов push_front) | front_inserter(list) |
std::inserter |
Вставка в указанную позицию | inserter(vec, it) |
Потоковые итераторы (настоящее спасение для упрощения ввода-вывода)
| Type | Функция | Пример |
|---|---|---|
std::istream_iterator |
Чтение данных из входного потока | istream_iterator<int>(cin) |
std::ostream_iterator |
Запись в выходной поток | ostream_iterator<int>(cout, " ") |
Синтаксис итераторов
Синтаксис итераторов обычно выглядит следующим образом:
#include <iterator>
// 使用迭代器遍历容器
for (ContainerType::iterator it = container.begin(); it != container.end(); ++it) {
// 访问元素 *it
}
Пример
Ниже приведён пример использования<iterator>Заголовочные файлы и обход итераторовstd::vectorпример:
Пример
#include <vector>
#include <iterator>
#include <algorithm>
int main() {
// Создание контейнера vector и его инициализация
std::vector<int> vec = {1, 2, 3, 4, 5};
// Перебор vector с использованием итераторов
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// Используйте ключевое слово auto для упрощения типов итераторов
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// Используйте диапазонный цикл for из C++11
for (int elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// Используйте back_inserter для автоматической вставки
std::vector<int> v2;
std::fill_n(std::back_inserter(v2), 3, 100);
// Используйте ostream_iterator для вывода
std::copy(v2.begin(), v2.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
Вывод:
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 100 100 100
Итог
<iterator>Основные функции можно свести к трём пунктам:
- Унифицированный способ доступа: разные контейнеры используют один и тот же набор логики обхода.
- Разделение контейнеров и алгоритмов: алгоритмы зависят только от итераторов.
- Улучшенная переиспользуемость кода: один и тот же фрагмент кода можно применять к нескольким структурам данных.
Начинающим рекомендуется в первую очередь освоить следующее:
next / prev / distanceback_inserter- Метод обхода с помощью итератора