Advantages of std::for_each over for loop


Question

Are there any advantages of std::for_each over for loop? To me, std::for_each only seems to hinder the readability of code. Why do then some coding standards recommend its use?

1
158
10/20/2012 9:08:16 PM

Accepted Answer

The nice thing with C++11 (previously called C++0x), is that this tiresome debate will be settled.

I mean, no one in their right mind, who wants to iterate over a whole collection, will still use this

for(auto it = collection.begin(); it != collection.end() ; ++it)
{
   foo(*it);
}

Or this

for_each(collection.begin(), collection.end(), [](Element& e)
{
   foo(e);
});

when the range-based for loop syntax is available:

for(Element& e : collection)
{
   foo(e);
}

This kind of syntax has been available in Java and C# for some time now, and actually there are way more foreach loops than classical for loops in every recent Java or C# code I saw.

167
10/31/2016 12:46:17 AM

Here are some reasons:

  1. It seems to hinder readability just because you're not used to it and/or not using the right tools around it to make it really easy. (see boost::range and boost::bind/boost::lambda for helpers. Many of these will go into C++0x and make for_each and related functions more useful.)

  2. It allows you to write an algorithm on top of for_each that works with any iterator.

  3. It reduces the chance of stupid typing bugs.

  4. It also opens your mind to the rest of the STL-algorithms, like find_if, sort, replace, etc and these won't look so strange anymore. This can be a huge win.

Update 1:

Most importantly, it helps you go beyond for_each vs. for-loops like that's all there is, and look at the other STL-alogs, like find / sort / partition / copy_replace_if, parallell execution .. or whatever.

A lot of processing can be written very concisely using "the rest" of for_each's siblings, but if all you do is to write a for-loop with various internal logic, then you'll never learn how to use those, and you'll end up inventing the wheel over and over.

And (the soon-to-be available range-style for_each):

for_each(monsters, boost::mem_fn(&Monster::think));

Or with C++x11 lambdas:

for_each(monsters, [](Monster& m) { m.think(); });

is IMO more readable than:

for(Monsters::iterator i = monsters.begin(); i != monsters.end(); ++i) {
    i->think();
} 

Also this (or with lambdas, see others):

for_each(bananas, boost::bind(&Monkey::eat, my_monkey, _1));

Is more concise than:

for(Bananas::iterator i = bananas.begin(); i != bananas.end(); ++i) {
    my_monkey->eat(*i);
} 

Especially if you have several functions to call in order... but maybe that's just me. ;)

Update 2: I've written my own one-liner wrappers of stl-algos that work with ranges instead of pair of iterators. boost::range_ex, once released, will include that and maybe it will be there in C++0x too?


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon