Reputation: 11439
I know historically it was better to use standard algorithms such as for_each
instead of a for
loop because they were just more readable. But I just feel like with c++11 the regular for loop is far more terse than the numerous standard algorithms with their corresponding callback functors.
Am I wrong to think this? Are many of the standard algorithms obsolete? What are the different benefits offered by those approaches?
Upvotes: 4
Views: 1576
Reputation: 2907
In terms of readability, using a range-based for is now probably slightly better than using std::for_each
. This doesn't necessarily means that for_each
is obsolete, though.
Consider this code:
auto myVals = getManyValsInAContainer();
for (auto& val : myVals)
{
doStuff(val);
}
It does the same thing that this less readable code:
auto myVals = getManyValsInAContainer();
for (auto it = myVals.begin(), end = myVals.end(); it != end; ++it)
{
doStuff(*it);
}
Now, let's say your container is an std::deque
, which means that your values are in big blocks of contiguous memory, with a few pointers to keep track of where those blocks are. For someone who knows the implementation, iterating over all elements of that container is easy: it simply requires a double loop to go through each element of each block.
But what about range-based for? It relies on operator++()
to move from one element to the next. Each time it does, operator++()
has to check whether the next element is in the same block or if it needs to proceed to the next block. Those calls are totally independent from each other, so there's no way to make things more efficient.
(Note: don't try to do things manually instead: you would need access to private parts of the container for that, and even if you had it, whatever you come up with would only work for some implementations of the STL but not others)
Is anything different when it comes to std::for_each
then? Well, for one thing it's a function template, so it can be specialized. It's also part of the STL, which means that the people who implemented it know exactly how std::deque
(or whatever other STL container you're using) is implemented, and that they can make std::for_each
a friend of the container classes (or do whatever else they need to do) to do things efficiently instead of relying on multiple calls to operator++()
.
So, there's your answer: std::for_each
is not obsolete. Readability was only one of the things it had going for it, but it's still more efficient than any for loop when iterating over an STL container.
Upvotes: 3
Reputation: 476970
Use your judgement.
Many algorithms have become much easier to use in C++11 thanks to lambdas and better bind expressions, which allow you to specify the functor in a relatively concise fashion. However, the range-based for
loop is a perfectly legitimate option, too.
If all you need is one or two statements in the loop body, then by all means use a range-based loop. If you need to call a member function on a collection of objects, maybe use for_each
and mem_fn
. If a bind expression looks clear enough, use it. But whatever you do, if you find yourself cramming too much logic into one place, consider refactoring and giving readable names to smaller components of work.
C++ offers you many tools, and the existence of one tool doesn't mean that another is useless. Large toolbelts, just like C++, target experienced users, and experience will let you choose the right tool for the right job.
Upvotes: 4
Reputation: 5240
This is going to be a rather subjective topic, but for what it's worth I agree with you. I think it's much better to use language constructs over library constructs, particularly when the language construct is concise and readable. (There was certainly an argument for readability of for_each
over prior to c++11 though)
Upvotes: 1