One recurring discussion point in one of our customers C++ project team is the following:
What is “the best” way to loop over collections?
In a typical scenario there is a standard container like std::list, or some equivalent collection, and the task is to do something with every element in the collection. The straight forward way would be like this:
std::list<std::string> mylist; for (std::list<std::string>::iterator iter = mylist.begin(); iter != mylist.end(); iter++) { ... }
This code is correct and readable. But my guess is that most of you instantly see at least two possible improvements:
- the call to mylist.end() occurs in every loop an can be expensive e.g. in case of long std::lists
- iter++ creates one unnecessary intermediate object on the stack
So this
for (std::list<std::string>::iterator iter = mylist.begin(), end = mylist.end(); iter != end; ++iter) { ... }
would be much better but can already be seen as a little less readable.
Using BOOST_FOREACH can save you much of this still tedious code but has one nasty pitfall when it comes to std::maps.
In some places of the code base std::for_each is used together with a function, or function object. The downside of this is that the function/function object code is not located where the loop occurs. However, this can be made “readable enough” when the function, or function object does only one thing and has a telling name.
Looping is sometimes done to create other collections of objects for each element. What to do there? Define the new collection use a for-loop of BOOST_FOREACH like above, or use std::transform with the same downside as std::for_each?
The other day one team member suggested to use boost::lambda expressions in loops. The initial usage examples where very promising but let me tell you – readability can drop dramatically very fast if you don’t be careful. It is very easy to get carried away with boost’s lambdas. I happened that we found ourselves having spent the last hour to carve out a super crisp lambda expression that takes anybody else another hour to read.
So the initial question remains undecided and will most likely stay like that. As for everything else in programming, there doesn’t seem to be a silver bullet for this task.
How do you go about looping in C++? Do you have some kind of coding style in place? Do you use std::for_each, BOOST_FOREACH, or some other means?
Looking forward to some feedback.
what about c++0x Lambdas? It’s already available in VC++2010 and GCC4.5 as far as I know.
“the call to mylist.end() occurs in every loop an can be expensive e.g. in case of long std::lists”
No, it can’t. The complexity of std::list::end is constant. It is in fact usually a single pointer dereference operation. It doesn’t get much cheaper than that.