При итерации по элементам вектора предпочтительнее использовать итераторы вместо индекса (см. Зачем использовать итераторы вместо индексов массива?).
std::vector<T> vec;
std::vector<T>::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
// do work
}
Однако может потребоваться использовать индекс в теле цикла. Что из следующего было бы предпочтительнее в этом случае с учетом производительности и гибкости / расширяемости?
std::vector vec;
size_t i;
for ( i = 0; i < vec.size(); ++i )
{
// use i
}





Использование std :: distance является немного более общим, поскольку оно работает для всех итераторов, а не только для итераторов с произвольным доступом. И он должен быть таким же быстрым, как It - vec.begin () в случае итераторов произвольного доступа.
Это - vec.begin () - это в основном арифметика указателей.
Вернитесь к индексированному циклу.
В основном в 90% случаев итераторы лучше, это один из тех 10%. Используя итератор, вы делаете код более сложным и, следовательно, трудным для понимания, тогда как вся причина использования итератора в первую очередь заключалась в упрощении вашего кода.
Я не могу сказать, что согласен. Тело цикла может содержать другой код, разыменовывающий итератор. Итераторы не предназначены для упрощения вашего кода, они делают ваш код более универсальным. Используя итераторы, вы можете поменять вектор на список, и он все равно будет работать.
Кроме того, итераторы std :: map или std :: set далеко не глупы. Если бы я перебрал все возможные ключи, это, вероятно, заняло бы вечность. Кроме того, мне пришлось бы выполнять поиск O (log (n)) для каждого ключа. Таким образом, мой цикл займет O (m * log (n)). Используя итератор, я мог перебрать коллекцию за время O (n).
Если вы планируете использовать исключительно вектор, вы можете вернуться к индексированному циклу, поскольку он передает ваше намерение более четко, чем цикл итератора. Однако, если развитие вашей программы в будущем может привести к смене контейнера, вам следует придерживаться итераторов и использовать std :: distance, который гарантированно работает со всеми стандартными итераторами.
Вам не хватает одного решения: сохраните индекс на случай, если он вам понадобится, но не используйте его как условие цикла. Работает и со списками, а стоимость (на цикл) составляет O (n) и дополнительный регистр.
Я всегда предпочитаю использовать итераторы в целях будущего развития.
В приведенном выше примере, если вы, возможно, решили заменить std :: vector на std :: set (возможно, вам нужна была уникальная коллекция элементов), использование итераторов и distance () продолжили бы работать.
Я почти уверен, что любые проблемы с производительностью будут оптимизированы до такой степени, что они станут незначительными.
Для векторов я всегда использую целочисленный метод. Каждый индекс в векторе имеет ту же скорость, что и поиск в массиве. Если я собираюсь часто использовать это значение, для удобства я создаю ссылку на него.
векторные итераторы могут быть немного быстрее, чем индекс в теории, поскольку они используют арифметику указателей для итерации по списку. Однако обычно я считаю, что удобочитаемость стоит минимальной разницы во времени выполнения.
Я использую итераторы для других типов контейнеров, а иногда и тогда, когда вам не нужна переменная цикла. Но если вам нужна переменная цикла, вы ничего не делаете, кроме того, что затрудняете ввод цикла. (Я не могу дождаться авто C++ 0x ..)
Забыл упомянуть о производительности, как правило, можно с уверенностью предположить, что индексированный цикл будет иметь лучшую производительность, но производительность будет очень похожей в обоих случаях.