Jump to content
  • Advertisement
Sign in to follow this  

less than opposed to not equal in for loops

This topic is 3120 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I had a question about how a for-loop should be set up. In C++ Primer, the author seems to use != instead of < in all the for-loops, but my question is, why? What if you set up a for loop as such: for (int i = 0; i != 11; i += 2) then you've got a problem, because i will never equal 11. I know that specific example is very easy to see the problem, but if you had something a little bit more complex, I assume it would be fairly hard to find the problem to fix it. Therefore, my question is: Why do you suppose != is used in C++ Primer, instead of <? I am thinking I might be missing something important that will change my theory, but it makes logical sense that < should be used instead. Thanks, dbproguy

Share this post


Link to post
Share on other sites
Advertisement
It depends on the context, but one reason != is sometimes used instead of < is that in the context of iterating over the elements in a container, != is more general. As an example, a generic function that iterates over the elements in a container using != as the conditional will work with (e.g.) both vector and map, whereas if < were used, the function would not work with map. Another way to look at it is that != will work with more types of iterators than will <.

In your example above, clearly != would not be the right choice (again, which to use depends on the context).

Share this post


Link to post
Share on other sites
A number of types which you can use as the counter in a for loop (in particular std::list::iterator), have no concept of ordering, and may not even implement the < operator. Not-equal is a concept which can be applied much more generally.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dbproguy

What if you set up a for loop as such:
for (int i = 0; i != 11; i += 2)
then you've got a problem, because i will never equal 11.

You've got a problem either way. If you're iterating over only the even numbers in a range, and that range may be of a size which is an odd number, then you had better think hard about what should be done in that situation. Using < instead of != would certainly hide the problem, but it wouldn't necessarily fix it. In general, the kind of bugs that you WANT to have are the ones that result in obvious problems. It's the ones that are less visible that are the real time sinks. From that perspective, using != instead of < is a good thing to do, because it doesn't hide the sort of problem you posted.

Share this post


Link to post
Share on other sites
So it's more of something to do when using iterators? In any case NOT using an iterator it's probably best to use the '<' operator though right? At least for the simple things

What would be the solution to iterating through the even numbered indexes of a container with an odd number? Would you just have to check and see if it has an odd number first then if it does, iterate to (x.end()-1)?

Share this post


Link to post
Share on other sites
Quote:
Original post by Dbproguy
What would be the solution to iterating through the even numbered indexes of a container with an odd number? Would you just have to check and see if it has an odd number first then if it does, iterate to (x.end()-1)?
It seems you missed the point.

Which one you use depends entirely on your algorithm.

If your algorithm must run less than x, use < x.
If your algorithm must run to the end of the iterator, use != foo.end().
If your algorithm must run as long as something is true, use x == true.
If you algorithm must run for {whatever}, use {the thing that does it}.


So if your algorithm has a requirement that the iterator have an even number of elements, it is your job to ensure this is the case. If your algorithm needs different logic to handle even and odd element counts, it is your job to ensure that it does.

If you need to advance an iterator more than one space, you can use std::advance() to move it. It is still your responsibility to ensure that you do not advance past the end of the container. Just note that if you iterate past the end of the iterator, your results are undefined. The standards committee intentionally left out requirements about what to do when you iterate past the end --- there are potential performance issues and they do not like forcing extra costs when it can be avoided.



The answer to your particular problem seems obvious to me:

Rather than incrementing directly inside the loop, consider writing a small function/functor/predicate/whatever that does this for you. This can advance it once, and if the result != iter.end(), advance it a second time. You could get fancy and have one that advances n times. Basically implement std::advance() with an end-of-iterator safety check.





For iterators, know that ordering is undefined. For any iterator, .begin() is not always before .end(). Reverse iterators go from back to front. Several standard containers operate in blocks so the data can be allocated in just about any configuration. I have seen several different circular buffer containers with an iterator that loops in the middle. In each case, ordering may not be what you expect.

Many beginners think of iterators in the format {front,...,end}. They need to revise their thinking. There are iterators that travel in reverse {end,...,front}, circular {...,end,empty,front,...}, block allocations {...,begin,...,end,...}, and just about any other configuration imaginable.

Because iterator ordering is undefined, you should always compare directly against .begin() and .end().

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by Dbproguy

What if you set up a for loop as such:
for (int i = 0; i != 11; i += 2)
then you've got a problem, because i will never equal 11.

You've got a problem either way. If you're iterating over only the even numbers in a range, and that range may be of a size which is an odd number, then you had better think hard about what should be done in that situation. Using < instead of != would certainly hide the problem, but it wouldn't necessarily fix it. In general, the kind of bugs that you WANT to have are the ones that result in obvious problems. It's the ones that are less visible that are the real time sinks. From that perspective, using != instead of < is a good thing to do, because it doesn't hide the sort of problem you posted.
Double edged sword.
You want any logic errors in your for-loop iteration or ending conditions to be obvious in a debug build, but on the other hand you may not want a runaway loop to happen for a customer, thus it may be safer to use less-than in a release build where you'd rather hide any problem.

It depends on the application too. Your for loop with != logic might be bug-free, but what's the risk of a runaway loop on say a spacecraft just because one bit of a variable got corrupted? Or a little closer to home... the memory in your electric fence controller got corrupted by a voltage spike? In some cases, correctness isn't necessarily the whole story. Things get interesting when it's more than just external data that you can't trust.

Share this post


Link to post
Share on other sites
If you want to hide it from the customer, but see it in development, why not:
assert(maxI % 2 == 0); // or your choice of debug-build-only error catching
for(int i = 0; i <= maxI; i += 2)
// ...
?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!