The std::for_each algorithm can be read as do something with all elements in range, which can improve readability. Say the action that you want to perform is 20 lines long, and the function where the action is performed is also about 20 lines long.
Range-based for loop (since C++11) Executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.
std::transform on a range For example, to obtain the keys that a map contains, you can use std::transform the following way: map<int, string> m = { {1,"foo"}, {42, "bar"}, {7, "baz"} }; vector<int> keys; std::transform(m. begin(), m. end(), std::back_inserter(keys), getFirst);
Foreach loop is used to iterate over the elements of a containers (array, vectors etc) quickly without performing initialization, testing and increment/decrement. The working of foreach loops is to do something for every element rather than doing something n times.
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.
Here are some reasons:
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.)
It allows you to write an algorithm on top of for_each that works with any iterator.
It reduces the chance of stupid typing bugs.
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, parallel 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) + lambdas:
for_each(monsters, [](auto& m) { m.think(); });
is IMO more readable than:
for (auto i = monsters.begin(); i != monsters.end(); ++i) {
i->think();
}
Also this:
for_each(bananas, [&](auto& b) { my_monkey.eat(b); );
Is more concise than:
for (auto i = bananas.begin(); i != bananas.end(); ++i) {
my_monkey->eat(*i);
}
But new range based for is probably the best:
for (auto& b : bananas)
my_monkey.eat(b);
But the for_each could be useful, especially if you have several functions to call in order but need to run each method for all objects before next... 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?
for_each
is more generic. You can use it to iterate over any type of container (by passing in the begin/end iterators). You can potentially swap out containers underneath a function which uses for_each
without having to update the iteration code. You need to consider that there are other containers in the world than std::vector
and plain old C arrays to see the advantages of for_each
.
The major drawback of for_each
is that it takes a functor, so the syntax is clunky. This is fixed in C++11 (formerly C++0x) with the introduction of lambdas:
std::vector<int> container;
...
std::for_each(container.begin(), container.end(), [](int& i){
i+= 10;
});
This will not look weird to you in 3 years.
Personally, any time I'd need to go out of my way to use std::for_each
(write special-purpose functors / complicated boost::lambda
s), I find BOOST_FOREACH
and C++0x's range-based for clearer:
BOOST_FOREACH(Monster* m, monsters) {
if (m->has_plan())
m->act();
}
vs
std::for_each(monsters.begin(), monsters.end(),
if_then(bind(&Monster::has_plan, _1),
bind(&Monster::act, _1)));
its very subjective, some will say that using for_each
will make the code more readable, as it allows to treat different collections with the same conventions.
for_each
itslef is implemented as a loop
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)
{
for ( ; first!=last; ++first ) f(*first);
return f;
}
so its up to you to choose what is right for you.
You're mostly correct: most of the time, std::for_each
is a net loss. I'd go so far as to compare for_each
to goto
. goto
provides the most versatile flow-control possible -- you can use it to implement virtually any other control structure you can imagine. That very versatility, however, means that seeing a goto
in isolation tells you virtually nothing about what's it's intended to do in this situation. As a result, almost nobody in their right mind uses goto
except as a last resort.
Among the standard algorithms, for_each
is much the same way -- it can be used to implement virtually anything, which means that seeing for_each
tells you virtually nothing about what it's being used for in this situation. Unfortunately, people's attitude toward for_each
is about where their attitude toward goto
was in (say) 1970 or so -- a few people had caught onto the fact that it should be used only as a last resort, but many still consider it the primary algorithm, and rarely if ever use any other. The vast majority of the time, even a quick glance would reveal that one of the alternatives was drastically superior.
Just for example, I'm pretty sure I've lost track of how many times I've seen people writing code to print out the contents of a collection using for_each
. Based on posts I've seen, this may well be the single most common use of for_each
. They end up with something like:
class XXX {
// ...
public:
std::ostream &print(std::ostream &os) { return os << "my data\n"; }
};
And their post is asking about what combination of bind1st
, mem_fun
, etc. they need to make something like:
std::vector<XXX> coll;
std::for_each(coll.begin(), coll.end(), XXX::print);
work, and print out the elements of coll
. If it really did work exactly as I've written it there, it would be mediocre, but it doesn't -- and by the time you've gotten it to work, it's difficult to find those few bits of code related to what's going on among the pieces that hold it together.
Fortunately, there is a much better way. Add a normal stream inserter overload for XXX:
std::ostream &operator<<(std::ostream *os, XXX const &x) {
return x.print(os);
}
and use std::copy
:
std::copy(coll.begin(), coll.end(), std::ostream_iterator<XXX>(std::cout, "\n"));
That does work -- and takes virtually no work at all to figure out that it prints the contents of coll
to std::cout
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With