- Pre-increment or Post-increment?
- Should I be using std::for_each?
- What is the best way to exit a multi-level for loop?
for loops should be used when you need to iterate over a sequence. Using != is the most concise method of stating the terminating condition for the loop. However, using a less restrictive operator is a very common defensive programming idiom. For integers it doesn't matter - it is just a personal choice without a more specific example. Looping over collections with iterators you want to use != for the reasons that others have stated. If you consider sequences of float or double, then you want to avoid != at all costs.
What I wanted to point out is that for is used when you need to iterate over a sequence. The generated sequence has a starting point, an interval, and a terminating condition. These are concisely specified within the for statement. If you find yourself either (1) not including the step portion of the for or (2) specifying something like true as the guard condition, then you should not be using a for loop!
The while loop is used to continue processing until a specific condition is met. If you are not processing a sequence, then you probably want a while loop instead. The guard condition arguments are similar here, but the decision between a while and a for loop should be a very conscious one. The while loop is under-appreciated in C++ circles IMO.
If you are processing a collection of items (a very common for-loop usage), then you really should use a more specialized method. Unfortunately, std::for_each is pretty painful in C++ for a number of reasons. In many cases separating the body of a for loop in a free-standing function (while somewhat painful) results in a much cleaner solution. When working with collections, consider std::for_each, std::transform, or std::accumulate. The implementation of many algorithms become concise and crystal clear when expressed in this manner. Not to mention that isolating the body of the loop into a separate function/method forces you to concentrate on the algorithm, its input requirements, and results.
If you are using Java, Python, Ruby, or even C++0x, then you should be using a proper collection foreach loop. As C++ compilers implement this feature, a number of for loops will disappear as will these types of discussions.
What I didn't delve into was the other discussion that has been going on for a few years now in the C++ expert circles. One side of the community really likes the Java-style foreach loops like:
Of course Microsoft went out and implemented their own version that looks like:
The Standards Working group seems to have settled on the Java version for what it's worth. The syntax is consistent with the existing language constructs and it does remove a lot of rather unnecessary boilerplate for iterating over containers. The following loop is the current method for iterating over a collection with a for loop:
That is a lot of typing in my opinion. And, Yes, I do know that typedef's exist to remove some of the overhead, but do I really want to typedef every single collection type?
The current alternative is refactor your loop body into a free standing function/functor and use std::for_each instead of a for loop. This seems like a lot of work for every loop in your program... and it is. For very simple loops, the benefit does not outweigh the cost. Just use a for loop. If you have a newer compiler that supports the Standard for loop, then use it and save some keystrokes.
There are quite a number of complex for loops out there. If you have a loop that is longer than about a half of a screen, then you should look into putting the body into a free standing function object. Try to minimize the coupling between the new functor and its surrounding environment. I know that closures are all the rage with the youngsters today and it is really cool to manipulate the calling environment from within another object, but this is one place were you want to strive for a stateless function object. If you can manage to have a completely stateless function, then it is possible to parallelize it by segmenting the problem space and running through each segment in parallel.
Now if you have a loop body that you just cannot make stateless, I would seriously question whether you should be using a for loop at all. Remember that for loops are for generating a sequence of values and iterating over them. If your algorithm is a recurrence algorithm in which the execution of a loop uses the output of the previous iteration as the input, then consider using something like std::accumulate instead. It more closely models what you need.
The other case of loops that I mention in the post are loops in which one of the portions of a for statement is absent. These are almost always while loops in disguise. If the initialization segment is absent, then you could be correct in using a for loop. If the condition or step segments are missing, then you should be using a while loop. The last special case is the infinite loop. These are usually represented by either for (;;) or while (true). I prefer the latter, but either are acceptable. That is, as long as you have verified that you need an infinite loop to begin with.
No comments:
Post a Comment