Guideline: while against

Disclaimer: I tried to find a similar question, however this came back to every question in C ++ ... I would also be grateful to everyone who could offer a better headline.

C ++ has two outstanding loop structures: while and for .

  • I deliberately ignore the do ... while construct, it's kind of unprecedented
  • I know std::for_each and BOOST_FOREACH , but not every loop is for each

Now I can be a little tight, but I always need to fix the code as follows:

 int i = 0; while ( i < 5) { // do stuff ++i; // I'm kind and use prefix notation... though I usually witness postfix } 

And convert it to:

 for (int i = 0; i < 5; ++i) { // do stuff } 

The for advantages in this example are several, in my opinion:

  • Locality : the variable I lives only in the loop area
  • Pack : the "control" loop is packed, so just looking at the declaration of the loop, I can understand whether it is correctly formed (and will be completed ...), assuming, of course, that the loop variable does not change in the body of the body
  • It can be embedded, although I would not always advise it (which leads to complex errors)

I have a tendency not to use while , with the possible exception for the while(true) idiom, but that’s not what I used for a while (pun intended). Even in difficult conditions, I tend to stick with the for construct, although on a few lines:

 // I am also a fan of typedefs for (const_iterator it = myVector.begin(), end = myVector.end(); it != end && isValid(*it); ++it) { /* do stuff */ } 

You can do this with while , of course, but then (1) and (2) will not be checked.

I would like to avoid “subjective” comments (like “I like it / better”), and I'm definitely interested in referring to existing coding rules / coding standards.

EDIT :

I try, as far as possible, to adhere to (1) and (2), (1), because it is recommended to localize the location → C ++ Encoding standards: Clause 18 and (2), because it simplifies maintenance if I do not need to scan the whole body loop to look for possible changes to the control variable (which I take for granted with for when the Third expression refers to loop variables).

However, as shown below, gf , although it has its own application:

 while (obj.advance()) {} 

Please note that this is not a claim to while , but an attempt to find which of while or for use depending on the case (and for reasons of common sense, and not just like it).

+6
c ++ coding-style
source share
9 answers

Not all loops for iteration:

 while(condition) // read eg: while condition holds { } 

okay while it seems forced:

 for(;condition;) { } 

You often see this for any input sources.

You can also have an implicit iteration:

 while(obj.advance()) { } 

Again, he looks compelled for.

In addition, when forcing instead of while people tend to abuse it:

 for(A a(0); foo.valid(); b+=x); // a and b don't relate to loop-control 
+7
source share

Functionally, they, of course, are one and the same. The only reason for differentiation is to give some meaning to a supporting or some human code reader / reviewer.

I think that the idiom is useful for communicating with the code reader, that the non-linear test controls the cycle, while for the idiom some sequence is usually implied. My brain also “expects” that for loops it only controls the section of the count expression for for arguments, and I am surprised (and disappointed) when I discover that someone is conditionally messing with an index variable inside an executable block.

You can put it in your coding standard so that "for" loops are used only when using the full loop loop construct: the index should be initialized in the initialization section, the index should be tested in the loop testing section, and the index value should only be changed in the expression section counter. Any code that wants to change the index in an executable block must use the while construct. The rationale would be "you can trust the for loop to execute, using only the conditions that you can see, without having to look for hidden instructions that change the index, but you cannot assume that this is true in the while loop."

I am sure that there are people who will argue and find many examples of counter examples to demonstrate proper use for operators that do not match my model above. This is great, but keep in mind that your code may be "unexpected" for an maintainer who may not have your understanding or brilliance. And it’s best to avoid surprises.

+4
source share

i does not automatically increase during the while loop.

 while (i < 5) { // do something with X if (X) { i++; } } 
+2
source share

One of the most beautiful things in C ++ is part of the STL algorithms. When reading code written correctly using STL, the programmer will read high-level loops instead of low-level "> .

+2
source share

I do not think that compilers can optimize much better if you decide to express your loop anyway. In the end, it all comes down to readability and that is a somewhat subjective question (although most people probably agree with the readability coefficient of most examples).

As you noticed, the for loop is a more compact way of saying

 type counter = 0; while ( counter != end_value ) { // do stuff ++counter; } 

While its syntax is flexible enough to allow you to do other things with it, I am trying to limit the use of for examples that are not much more complicated than the above. OTOH, I would not use a while for the above.

+1
source share

I usually use for loops when some kind of count happens, and the loop ends when the count ends. Obviously, you have a standard for( i=0; i < maxvalue; i++ ) , but also things like for( iterator.first(); !iterator.is_done(); iterator.next() ) .

I use while loops when it is not clear how many times the loop can iterate, i.e. "cycle" until a condition is fulfilled that cannot be pre-calculated (or is not satisfied). "

0
source share
 // I am also a fan of typedefs for (const_iterator it = myVector.begin(), end = myVector.end(); it != end && isValid(*it); ++it) { /* do stuff */ } 

It seems to me that the code above is less readable than the code below.

 // I am also a fan of typedefs const_iterator it = myVector.begin(); end = myVector.end(); while(it != end && isValid(*it)) { /* do stuff */ ++it} 

Personally, I believe that legibility surpasses these formatting standards. If another programmer cannot read your code easily, this will lead to errors in the worst case, and in the best case, it will lead to wasted time that the company costs.

0
source share

In Ye Olde C, the while and while loops were not the same.

The difference was that for for loops, the compiler could freely assign a variable to the CPU register and return the register after the loop. Thus, such code had undefined behavior:

 int i; for (i = 0; i < N; i++) { if (f(i)) break; } printf("%d", i); /* Non-defined behaviour, unexpected results ! */ 

I am not 100% sure, but I believe that this is described in K & R

This is normal:

 int i = 0; while (i < N) { if (f(i)) break; i++; } printf("%d", i); 

Of course, it depends on the compiler. In addition, over time, compilers ceased to use this freedom, so if you run the first code in a modern C compiler, you should get the expected results.

0
source share

I would not throw out do-while loops so quickly. They are useful if you know that the body of the cycle will work at least once. Consider some code that creates a single thread for the processor core. With a for loop, you might see:

 for (int i = 0; i < number_of_cores; ++i) start_thread(i); 

When the loop starts, the first thing that is checked is a condition, in the case of number_of_cores it is 0, in which case the loop body should never be started. Hold on, though - this is an absolutely unnecessary test! The user will always have at least one core, otherwise how does the current code work? The compiler cannot eliminate the first redundant comparison, as far as number_of_cores is known to be 0. But the programmer knows better. So, eliminating the first comparison:

 int i = 0; do { start_thread(i++); } while (i < number_of_cores); 

Now, every time this cycle hits, on a single-core computer there is only one comparison instead of two (with a for loop, the condition is true for i = 0, false for i = 1, while do while is false all the time). The first comparison is omitted, therefore it is faster. With less branching potential, there are fewer opportunities for incorrect industry predictions, so they are faster. Since the while condition is currently more predictable (always false on 1-core), the branch predictor can do a better job, which is faster.

A slight nitpick, but not something that needs to be thrown away - if you know that the body will work at least once, it is premature pessimization to use the for loop.

0
source share

All Articles