for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
... vs ...
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
Для меня [последнее видно в надстроек] выглядит сложнее, и я не понимаю, почему это лучше, чемодин я использовал.
Я бы сказал, что это выглядело бы более сложным для любого, у кого нет какой-либо конкретной причины любить последнее в той степени, в которой оно искажает восприятие.Но давайте перейдем к тому, почему это может быть лучше ....
Можете ли вы сказать мне, почему эта версия лучше?Или это не имеет значения для простых вещей, таких как печать элементов вектора?I! = Values.end () замедляет итерацию?
it_end
Производительность : it_end
получает значение end()
только один раз, какначало цикла.Для любого контейнера, где вычисление end()
было слишком дорогим, его вызов только один раз может сэкономить процессорное время.Для любой наполовину достойной реальной библиотеки C ++ Standard все функции end()
не выполняют вычислений и могут быть встроены для эквивалентной производительности.На практике, если нет некоторого шанса, что вам может понадобиться добавить нестандартный контейнер с более дорогой функцией end()
, нет смысла явно «кэшировать» end()
в оптимизированном коде.
ЭтоИнтересно, поскольку для vector
это означает, что size()
может потребовать небольшого вычисления - концептуально вычесть begin()
из end()
, а затем разделить на sizeof(value_type)
(компиляторы масштабируются по размеру неявно во время арифметики с указателями), например, GCC 4.5.2:
size_type size() const
{ return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
Обслуживание : если код эволюционирует для вставки или удаления элементов внутри цикла (очевидно, что итератор сам по себе не признан недействительным - вероятным для карт / наборов / списков и т. д.) это еще одна точка обслуживания (и, следовательно, вероятность ошибок), если кешированное значение end()
также необходимо явно пересчитать.
Небольшая деталь, но здесь vec
должно быть typedef
, и IMHO часто лучше использовать typedef для контейнеров, так какослабляетСоединение контейнерного типа с доступом к типам итераторов.
type identifier(expr)
Стиль и документальный акцент :type identifier(expr)
более точно указывает на вызов конструктора, чем type identifier = expr
, что является основной причиной, по которой некоторые люди предпочитают форму.Я обычно предпочитаю последнее, поскольку мне нравится подчеркивать смысл присваивания ... это визуально однозначно, тогда как нотация вызова функции используется для многих вещей.
Почти эквивалентность: Для большинства классов оба в любом случае вызывают один и тот же конструктор, , но , если type
имеет явный конструктор типа expr
, он будет передан, если =
используется.Хуже того, некоторые другие преобразования могут позволить использовать менее идеальный конструктор.Например, X x = 3.14;
будет проходить через explicit X::X(double);
, чтобы соответствовать X::X(int)
- вы можете получить менее точный (или просто неверный) результат - но я еще не укушен такой проблемой, так что это довольно теоретически!
Или это const_iterator против итератора?Является ли const_iterator быстрее в цикле, подобном этому?
Для стандартных контейнеров const_iterator
и iterator
работают одинаково, но последний подразумевает, что вы хотите изменить элементы во время итерации.Используя const_iterator
документы, которые вы не собираетесь делать, и компилятор обнаружит любое противоречивое использование итератора, который пытается изменить.Например, вы не сможете случайно увеличить значение, которое адресует итератор, когда намереваетесь увеличить сам итератор.
Учитывая, что C ++ 0x упоминается в других ответах - но только дополнительное преимуществоauto
и cbegin
/ cend
- также поддерживается новая запись:
for (const Foo& foo: container)
// use foo...