Обычно итераторы используются для линейного доступа к элементам контейнера; однако с помощью «итераторов произвольного доступа» можно получить доступ к любому элементу таким же образом, как и operator[]
.
Для доступа к произвольным элементам вектора vec
вы можете использовать следующее:
vec.begin() // 1st
vec.begin()+1 // 2nd
// ...
vec.begin()+(i-1) // ith
// ...
vec.begin()+(vec.size()-1) // last
Ниже приведен пример типичного шаблона доступа (более ранние версии C ++):
int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
Преимущество использования итератора в том, что вы можете применить тот же шаблон к другим контейнерам :
sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
sum += *it;
}
По этой причине очень легко создать код шаблона, который будет работать одинаково независимо от типа контейнера . Еще одно преимущество итераторов состоит в том, что они не предполагают, что данные находятся в памяти; например, можно создать прямой итератор, который может считывать данные из входного потока или просто генерирует данные на лету (например, генератор диапазона или случайных чисел).
Другой вариант использования std::for_each
и лямбды:
sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });
Начиная с C ++ 11 вы можете использовать, auto
чтобы не указывать очень длинное и сложное имя типа итератора, как было показано ранее (или даже более сложное):
sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
И, кроме того, для каждого варианта есть более простой вариант:
sum = 0;
for (auto value : vec) {
sum += value;
}
И, наконец, std::accumulate
нужно быть осторожным при добавлении целых чисел или чисел с плавающей запятой.