Это зависит.
Сила for_each
в том, что вы можете использовать его с любым контейнером, итераторы которого удовлетворяют концепции входного итератора, и, таким образом, он обычно используется в любом контейнере. Это повышает удобство обслуживания таким образом, что вы можете просто поменять контейнер и не нужно ничего менять. То же самое не относится к циклу над size
вектора. Единственными другими контейнерами, с которыми вы могли бы поменять его без необходимости изменения цикла, был бы другой случайный доступ.
Теперь, если вы напечатаете версию итератора самостоятельно, типичная версия выглядит следующим образом:
// substitute 'container' with a container of your choice
for(std::container<T>::iterator it = c.begin(); it != c.end(); ++it){
// ....
}
Довольно долго, а? C ++ 0x избавляет нас от этой длины с ключевым словом auto
:
for(auto it = c.begin(); it != c.end(); ++it){
// ....
}
Уже приятнее, но все же не идеально. Вы звоните end
на каждой итерации, и это можно сделать лучше:
for(auto it = c.begin(), ite = c.end(); it != ite; ++it){
// ....
}
Хорошо выглядит сейчас. Тем не менее, дольше, чем эквивалент for_each
версия:
std::for_each(c.begin(), c.end(), [&](T& item){
// ...
});
С "эквивалентом", являющимся слегка субъективным, так как T
в списке параметров лямбды может быть некоторым подробным типом, таким как my_type<int>::nested_type
. Тем не менее, можно typedef
обойти это. Честно говоря, я до сих пор не понимаю, почему лямбды не могли быть полиморфными с выводом типа ...
Теперь еще одна вещь, которую следует учитывать, это то, что for_each
, само имя, уже выражает намерение. Он говорит, что ни один элемент в последовательности не будет пропущен, что может быть в случае с обычным циклом for.
Это подводит меня к другому моменту: поскольку for_each
предназначен для выполнения всей последовательности и применения операции к каждому элементу в контейнере, он не предназначен для ранней обработки return
s. или break
с в целом. continue
можно смоделировать с помощью оператора return
от лямбды / функтора.
Итак, используйте for_each
, где вы действительно хотите применить операцию к каждому элементу в коллекции.
С другой стороны, for_each
может быть просто "устаревшим" с C ++ 0x благодаря удивительным циклам for, основанным на диапазоне (также называемых циклами foreach):
for(auto& item : container){
// ...
}
Что намного короче (yay) и допускает все три варианта:
- возвращение рано (даже с возвращаемым значением!)
- разрыв из цикла и
- пропуская некоторые элементы.