++i or i++ in for loops ??

107,591

Solution 1

For integers, there is no difference between pre- and post-increment.

If i is an object of a non-trivial class, then ++i is generally preferred, because the object is modified and then evaluated, whereas i++ modifies after evaluation, so requires a copy to be made.

Solution 2

++i is slightly more efficient due to its semantics:

++i;  // Fetch i, increment it, and return it
i++;  // Fetch i, copy it, increment i, return copy

For int-like indices, the efficiency gain is minimal (if any). For iterators and other heavier-weight objects, avoiding that copy can be a real win (particularly if the loop body doesn't contain much work).

As an example, consider the following loop using a theoretical BigInteger class providing arbitrary precision integers (and thus some sort of vector-like internals):

std::vector<BigInteger> vec;
for (BigInteger i = 0; i < 99999999L; i++) {
  vec.push_back(i);
}

That i++ operation includes copy construction (i.e. operator new, digit-by-digit copy) and destruction (operator delete) for a loop that won't do anything more than essentially make one more copy of the index object. Essentially you've doubled the work to be done (and increased memory fragmentation most likely) by simply using the postfix increment where prefix would have been sufficient.

Solution 3

++i is a pre-increment; i++ is post-increment.
The downside of post-increment is that it generates an extra value; it returns a copy of the old value while modifying i. Thus, you should avoid it when possible.

Solution 4

With integers, it's preference.

If the loop variable is a class/object, it can make a difference (only profiling can tell you if it's a significant difference), because the post-increment version requires that you create a copy of that object that gets discarded.

If creating that copy is an expensive operation, you're paying that expense once for every time you go through the loop, for no reason at all.

If you get into the habit of always using ++i in for loops, you don't need to stop and think about whether what you're doing in this particular situation makes sense. You just always are.

Solution 5

There is a reason for this: performance. i++ generates a copy, and that's a waste if you immediately discard it. Granted, the compiler can optimize away this copy if i is a primitive, but it can't if it isn't. See this question.

Share:
107,591
Ismail Marmoush
Author by

Ismail Marmoush

You can check my website and blog https://marmoush.com

Updated on July 08, 2022

Comments

  • Ismail Marmoush
    Ismail Marmoush almost 2 years

    Possible Duplicate:
    Is there a performance difference between i++ and ++i in C++?

    Is there a reason some programmers write ++i in a normal for loop instead of writing i++?

  • John Dibling
    John Dibling over 13 years
    This is disingenous. In almost every single case, the performance of ++i and i++ is exactly the same.
  • Drew Hall
    Drew Hall over 13 years
    That's probably true for int-like indices, but not generally true for iterators and other objects that might act as indices.
  • rtpg
    rtpg over 13 years
    doesn't i++ and ++i call the same operator?
  • SingleNegationElimination
    SingleNegationElimination over 13 years
    Although the same code is generated with integers, because of the second paragraph, it's probably a good idea to go with ++i for all types, so that you are in the habit of using it for all types.
  • Oliver Charlesworth
    Oliver Charlesworth over 13 years
    @Token: I agree in principle. However, i++ is somewhat idiomatic in C code; if you regularly use both languages, it can get confusing...
  • Jim Mischel
    Jim Mischel over 13 years
    Pardon my ignorance here, but this sure sounds silly. Imagine that i is an instance of some class that overloads the increment operator. Are you saying that if I were to simply post-increment (not in a loop control statement, but rather just increment it) (i.e. i++;), that the compiler wouldn't be able to see that I'm not doing anything with the return value, and automatically re-write that to be ++i?
  • fredoverflow
    fredoverflow over 13 years
    No, ++i calls i.operator++() and i++ calls i.operator(int). See my answer for implementation details.
  • Drew Hall
    Drew Hall over 13 years
    @John: Not disingenuous at all. For iterator objects, the compiler has no reason to even expect some sort of equivalence between prefix and postfix increment (the class designer can make them perform arbitrarily different actions)--it must call the postfix form (with resulting copy). For heavyweight iterators and otherwise lightweight loops, the performance hit can be significant. As an example, what if i is not an int or a std::vector<int>::iterator, but instead a BigInteger or equivalent. The copy is unneccessary and should just be avoided, period.
  • Steve Jessop
    Steve Jessop over 13 years
    @Jim: the compiler has to call the relevant operator overload (operator++() or operator++(int) for preincrement and postincrement respectively). If they're actually equivalent, and if the call is inlined, and if the copies involved are all removed by the optimizer, then the emitted code may end up the same - try it. But the compiler certainly can't replace one with the other solely on the basis that the result is unused. I don't especially care, because I write ++i for clarity (as I perceive it). "increment i" -> "++i".
  • Drew Hall
    Drew Hall over 13 years
    @Jim Mischel: The compiler can see that the return value isn't being used, but it has no reason to expect that ++i and i++ have the same semantics modulo the copy. So it has to call the version that the programmer asked for.
  • Jim Mischel
    Jim Mischel over 13 years
    egads, it's been so long, I forgot that post-increment and pre-increment are two entirely different operators in C++, which can be overloaded independently. Thanks.
  • John Dibling
    John Dibling over 13 years
    @Drew: In that case, the programmer is going to know it (or should, anyway) and my disclaimer that "if you have to ask, it doesnt matter" wont apply. The question was about "normal for loop"s. Performance has nothing to do with it. Its all about personal style.
  • Steve Jessop
    Steve Jessop over 13 years
    I think "must make a copy" is overstating it a bit. If the result is unused, and the operator and the copy constructor can both be completely inlined, as is commonly the case with iterators, then it should be a sitting duck for the optimizer to remove copy entirely - unused value with no side-effects. ++i does save you wondering whether the optimization was successful, and more importantly it just obviously makes more sense ;-)
  • M2tM
    M2tM over 13 years
    John Dibling: "Normal for loops" typically involve iterators.
  • Drew Hall
    Drew Hall over 13 years
    @John: Perhaps. I guess I just consider it a good habit to be in--there is no downside to always writing ++i, but there is (sometimes) a downside to writing i++.
  • John Dibling
    John Dibling over 13 years
    @Drew: I don't dispute it being a good habit to be in. In fact I do the same thing.
  • Martin York
    Martin York over 13 years
    The second reason is a good reason to always use the prefix ++. The reason being that code is always being modified, and what is an integer (pointer) today will become an iterator tomorrow. Thus you want to be able to change the type without having to go through all the code and change its usage.
  • sbi
    sbi over 13 years
    @Oli: Heavens forbid that code being idiomatic in C would be a good reason to use it in C++ as well!
  • Ajk_P
    Ajk_P over 9 years
    100% agreed with what @FredOverflow said. Think of it this way, there is no reason to write i++, but there might be a reason to write ++i.
  • s g
    s g about 8 years
    Great and succinct example
  • Mouradif
    Mouradif over 7 years
    I want to upvote your answer but then it wont be rated 42 anymore
  • wizzwizz4
    wizzwizz4 almost 7 years
    @KiJéy You can come back to do it now. (But then it won't be rated 64 anymore...)
  • Mouradif
    Mouradif almost 7 years
    @wizzwizz4 let's get this to 128