awksp awksp - 2 months ago 6
C++ Question

Is there any basis for this alternative 'for' loop syntax?

I came across a set of slides for a rant talk on C++. There were some interesting tidbits here and there, but slide 8 stood out to me. Its contents were, approximately:


Ever-changing styles



Old and busted:



for (int i = 0; i < n; i++)


New hotness:



for (int i(0); i != n; ++i)



I'd never seen a
for
loop using the second form before, so the claim that it was the "New hotness" interested me. I can see some rationale for it:


  1. Direct initialization using a constructor vs copy initialization

  2. !=
    could be faster in hardware than
    <

  3. ++i
    doesn't require the compiler to keep the old value of
    i
    around, which is what
    i++
    would do.



I'd imagine that this is premature optimization, though, as modern optimizing compilers would compile the two down to the same instructions; if anything, the latter is worse because it isn't a "normal"
for
loop. Using
!=
instead of
<
is also suspicious to me, because it makes the loop semantically different than the original version, and can lead to some rare, but interesting, bugs.

Was there any point where the "New hotness" version of the
for
loop was popular? Is there any reason to use that version these days (2016+), e.g. unusual loop variable types?

Answer
  1. Direct initialization using a constructor vs copy initialization

    These are exactly identical for ints and will generate identical code. Use whichever one you prefer to read or what your code policies are, etc.

  2. != could be faster in hardware than <

    The generated code won't actually be i < n vs i != n, it'll be like i - n < 0 vs i - n == 0. That is, you'll get a jle in the first case and a je in the second case. All the jcc instructions have identical performance (see instruction set reference and optionization reference, which just list all the jcc instructions together as having throughput 0.5).

    Which is better? For ints, probably doesn't matter performance-wise.

    Strictly safer to do < in case you want to skip elements in the middle, since then you don't have to worry about ending up with an infinite/undefined loop. But just write the condition that makes the most sense to write with the loop that you're writing. Also take a look at dasblinkenlight's answer.

  3. ++i doesn't require the compiler to keep the old value of i around, which is what i++ would do.

    Yeah that's nonsense. If your compiler can't tell that you don't need the old value and just rewrite the i++ to ++i, then get a new compiler. Those definitely will compile to the same code with identical performance.

    That said, it's a good guideline to just use the right thing. You want to increment i, so that's ++i. Only use post-increment when you need to use post-increment. Full stop.


That said, the real "new hotness" would definitely be:

for (int i : range(n)) { ... }
Comments