Компилятор может быть в состоянии оптимизировать второе в первое, но это предполагает, что оба они эквивалентны, то есть end () фактически является константой. Немного более проблемная проблема заключается в том, что компилятор может быть не в состоянии сделать вывод, что конечный итератор постоянен из-за возможного наложения имен. Тем не менее, если предположить, что вызов end () встроен, разница заключается только в загрузке памяти.
Обратите внимание, что это предполагает, что оптимизатор включен. Если оптимизатор не включен, как это часто делается в отладочных сборках, то вторая формулировка будет включать в себя N-1 больше вызовов функций. В текущих версиях Visual C ++ отладочные сборки также будут подвергаться дополнительным ударам из-за проверки пролога / эпилога функции и более тяжелых итераторов отладки. Следовательно, в тяжелом коде STL по умолчанию в первом случае можно предотвратить непропорционально медленный код в отладочных сборках.
Вставка и удаление в цикле возможны, как указывали другие, но с таким типом цикла я считаю это маловероятным. Во-первых, контейнеры на основе узлов - list, set, map - не аннулируют end () ни в одной из операций. Во-вторых, приращение итератора часто необходимо перемещать в цикле, чтобы избежать проблем с аннулированием:
// assuming list -- cannot cache end() for vector
iterator it(c.begin()), end(c.end());
while(it != end) {
if (should_remove(*it))
it = c.erase(it);
else
++it;
}
Таким образом, я считаю цикл, который утверждает, что вызывает end () по причинам, связанным с изменением цикла во время цикла, и который до сих пор имеет ++ в заголовке цикла, как подозрительный.