Incrementing in C++ - When to use x++ or ++x?
Asked Answered
D

12

126

I'm currently learning C++ and I've learned about the incrementation a while ago. I know that you can use "++x" to make the incrementation before and "x++" to do it after.

Still, I really don't know when to use either of the two... I've never really used "++x" and things always worked fine so far - so, when should I use it?

Example: In a for loop, when is it preferable to use "++x"?

Also, could someone explain exactly how the different incrementations (or decrementations) work? I would really appreciate it.

Dionysiac answered 28/11, 2009 at 16:45 Comment(0)
U
169

It's not a question of preference, but of logic.

x++ increments the value of variable x after processing the current statement.

++x increments the value of variable x before processing the current statement.

So just decide on the logic you write.

x += ++i will increment i and add i+1 to x. x += i++ will add i to x, then increment i.

Unlimited answered 28/11, 2009 at 16:47 Comment(11)
and please note that in a for loop, on primatives, there is absolutely no difference. Many coding styles will recommend never using an increment operator where it could be misunderstood; i.e., x++ or ++x should only exist on its own line, never as y=x++. Personally, I don't like this, but it's uncommonBranch
And if used on its own line, the generated code is almost sure to be the same.Kast
This may seem like pedantry (mainly because it is :) ) but in C++, x++ is a rvalue with the value of x before increment, x++ is an lvalue with the value of x after an increment. Neither expression guarantees when the actual incremented value is stored back to x, it is only guaranteed that it happens before the next sequence point. 'after processing the current statement' is not strictly accurate as some expressions have sequence points and some statements are compound statements.Ankerite
Actually, the answer is misleading. The point in time where the variable x is modified probably doesn't differ in practice. The difference is that x++ is defined to return an rvalue of the previous value of x while ++x still refers to the variable x.Witless
@Charles: You're absolutely right to be "pedantic" here. Sequence points etc. are not well understood and especially that this has been marked as the answer it should be fixed.Pingpingpong
@BeowulfOF: I really think it worth rewording your answer so that it does not imply when the side-effects take place....Pingpingpong
what side effects? I mean what goes on inside is less important if the effect seen is correct, isn't it? The answer from duffymo says exact the same thing only as quote from a book.Unlimited
@BeowulfOF: The answer implies an order which doesn't exist. There is nothing in the standard to say when the increments take place. The compiler is entitled to implement "x += i++" as: int j = i; i=i+1 ; x += j;" (ie. 'i' incremented before "processing the current statement"). This is why "i = i++" has undefined behaviour and its why I think the answer needs "tweaking". The description of "x += ++i" is correct as there is no suggestion of order: "will increment i and add i+1 to x".Pingpingpong
you are using the same words: "'i' increments before processing the current statement" - I do not imply when exactly the increment is done - but the variable is incremented before processing the statement (++i) or the statement is processed before the increment is done (i++) -> to work with it its correct and easy to remember, no words about exactly when the increment is done or whether additional helper vars are used.Unlimited
@BeowulfOF: In my comment, my words refer to the code in the comment, and I explicitly use those words as they say they contradict the words you've used in your answer. And yet again in your comment you've said: "but the variable is incremented before processing the statement (++i)". This is just not true. The result of (++i) be "i+1" but there's no guarantee that the variable will have this value at that time. The expression "x+= <result>" can be evaluated, x modified and THEN 'i' updated.Pingpingpong
And, ++x is Lvalue while x++ is Rvalue. This is mathematically meaningless, however, sometimes in expressions it's very important.Lonely
S
59

Scott Meyers tells you to prefer prefix except on those occasions where logic would dictate that postfix is appropriate.

"More Effective C++" item #6 - that's sufficient authority for me.

For those who don't own the book, here are the pertinent quotes. From page 32:

From your days as a C programmer, you may recall that the prefix form of the increment operator is sometimes called "increment and fetch", while the postfix form is often known as "fetch and increment." The two phrases are important to remember, because they all but act as formal specifications...

And on page 34:

If you're the kind who worries about efficiency, you probably broke into a sweat when you first saw the postfix increment function. That function has to create a temporary object for its return value and the implementation above also creates an explicit temporary object that has to be constructed and destructed. The prefix increment function has no such temporaries...

Schoonmaker answered 28/11, 2009 at 16:49 Comment(5)
If the compiler doesn't realize that the value before the increment is unnessescary, it might implement the postfix increment in several instructions - copy the old value, and then increment. The prefix increment should always just be one instruction.Orsa
I happened to test this yesterday with gcc: in a for loop in which the value is thrown away after executing i++ or ++i, the generated code is the same.Buzzer
Try it outside the for loop. The behavior in an assignment must be different.Schoonmaker
I explicitly disagree with Scott Meyers on his second point - it is usually irrelevant since 90% or more cases of "x++" or "++x" are typically isolated from any assignment, and optimizers are smart enough to recognise that no temporary variables need be created in such cases. In that case, the two forms are completely interchangeable. The implication of this is that old code bases riddled with "x++" should be left alone - you're more likely to introduce subtle errors changing them to "++x" than to improve performance anywhere. Arguably it is better to use "x++" and make people think.Scharf
You can trust Scott Meyers all you want, but if your code is so performance-dependent that any performance difference between ++x and x++ actually matters, it's a lot more important that you actually use a compiler that can completely and properly optimize either version no matter what the context. "Since I'm using this crappy old hammer, I can only drive nails in at a 43.7-degree angle" is a poor argument for building a house by driving nails in at only 43.7 degrees. Use a better tool.Franchot
H
35

From cppreference when incrementing iterators:

You should prefer pre-increment operator (++iter) to post-increment operator (iter++) if you are not going to use the old value. Post-increment is generally implemented as follows:

   Iter operator++(int)   {
     Iter tmp(*this); // store the old value in a temporary object
     ++*this;         // call pre-increment
     return tmp;      // return the old value   }

Obviously, it's less efficient than pre-increment.

Pre-increment does not generate the temporary object. This can make a significant difference if your object is expensive to create.

Hawthorne answered 28/11, 2009 at 16:57 Comment(0)
H
8

I just want to notice that the geneated code is offen the same if you use pre/post incrementation where the semantic (of pre/post) doesn't matter.

example:

pre.cpp:

#include <iostream>

int main()
{
  int i = 13;
  i++;
  for (; i < 42; i++)
    {
      std::cout << i << std::endl;
    }
}

post.cpp:

#include <iostream>

int main()
{

  int i = 13;
  ++i;
  for (; i < 42; ++i)
    {
      std::cout << i << std::endl;
    }
}

_

$> g++ -S pre.cpp
$> g++ -S post.cpp
$> diff pre.s post.s   
1c1
<   .file   "pre.cpp"
---
>   .file   "post.cpp"
Huerta answered 28/11, 2009 at 17:19 Comment(2)
For a primitive type like an integer, yes. Have you checked to see what the difference turns out to be for something like a std::map::iterator? Of course there the two operators are different, but I'm curious as to whether the compiler will optimize postfix to prefix if the result is not used. I don't think it's allowed to -- given that the postfix version could contain side effects.Plaza
Also, 'the compiler will probably realise you don't need the side effect and optimise it away' should not be an excuse to write sloppy code that uses the more complex postfix operators without any reason whatsoever, aside from presumably the fact that so many supposed teaching materials use postfix for no apparent reason and get copied around wholesale.Leitmotif
T
8

The most important thing to keep in mind, imo, is that x++ needs to return the value before the increment actually took place -- therefore, it has to make a temporary copy of the object (pre increment). This is less effecient than ++x, which is incremented in-place and returned.

Another thing worth mentioning, though, is that most compilers will be able to optimize such unnecessary things away when possible, for instance both options will lead to same code here:

for (int i(0);i<10;++i)
for (int i(0);i<10;i++)
Tooley answered 28/11, 2009 at 22:56 Comment(1)
Is the temporary copy also the case for such cases where we use it alone in a line to increment a variable during a loop? e.g. Is there any difference for m between int m=0; for (int i(0);i<10;++i) m++; and int m=0; for (int i(0);i<10;++i) ++m; ?Boylan
B
5

I agree with @BeowulfOF, though for clarity I would always advocate splitting the statements so that the logic is absolutely clear, i.e.:

i++;
x += i;

or

x += i;
i++;

So my answer is if you write clear code then this should rarely matter (and if it matters then your code is probably not clear enough).

Bonkers answered 28/11, 2009 at 16:57 Comment(0)
A
5

If count{5};

If you use ++count it will be process beforethe statement

total = --count +6;

Total will be equal to 10

If you use count++ it will be process after the statement

total = count-- +6;

Total will be equal to 11

Aztec answered 16/9, 2021 at 9:15 Comment(2)
Why is the "after" statement any different? 5 + 6 would be 11, and then if the -- takes effect, total is still 10. Correct?Thumbscrew
total = --count + 6 is equivalent to count = count - 1;total = count+6; while total = count-- + 6 is equivalent to total = count + 6; count = count - 1; The order of statement being different, the result is different.Warfold
A
2

Just wanted to re-emphasize that ++x is expected to be faster than x++, (especially if x is an object of some arbitrary type), so unless required for logical reasons, ++x should be used.

Another answered 28/11, 2009 at 16:57 Comment(1)
I just want to emphasise that this emphasis is more than likely misleading. If you're looking at some loop that ends with an isolated "x++" and thinking "Aha! - that's the reason this is running so slow!" and you change it to "++x", then expect precisely no difference. Optimisers are smart enough to recognise that no temporary variables need be created when nobody is going to use their results. The implication is that old code bases riddled with "x++" should be left alone - you're more likely to introduce errors changing them than to improve performance anywhere.Scharf
L
2

Postfix form of ++,-- operator follows the rule use-then-change ,

Prefix form (++x,--x) follows the rule change-then-use.

Example 1:

When multiple values are cascaded with << using cout then calculations(if any) take place from right-to-left but printing takes place from left-to-right e.g., (if val if initially 10)

 cout<< ++val<<" "<< val++<<" "<< val;

will result into

12    10    10 

Example 2:

In Turbo C++, if multiple occurrences of ++ or (in any form) are found in an expression, then firstly all prefix forms are computed then expression is evaluated and finally postfix forms are computed e.g.,

int a=10,b;
b=a++ + ++a + ++a + a;
cout<<b<<a<<endl;

It's output in Turbo C++ will be

48 13

Whereas it's output in modern day compiler will be (because they follow the rules strictly)

45 13
  • Note: Multiple use of increment/decrement operators on same variable in one expression is not recommended. The handling/results of such
    expressions vary from compiler to compiler.
Laband answered 7/11, 2015 at 7:27 Comment(1)
It's not that expressions containing multiple inc/decrement operations "vary from compiler to compiler", but rather worse: such multiple modifications between sequence points have undefined behaviour and poison the program.Leitmotif
C
1

You explained the difference correctly. It just depends on if you want x to increment before every run through a loop, or after that. It depends on your program logic, what is appropriate.

An important difference when dealing with STL-Iterators (which also implement these operators) is, that it++ creates a copy of the object the iterator points to, then increments, and then returns the copy. ++it on the other hand does the increment first and then returns a reference to the object the iterator now points to. This is mostly just relevant when every bit of performance counts or when you implement your own STL-iterator.

Edit: fixed the mixup of prefix and suffix notation

Chert answered 28/11, 2009 at 16:51 Comment(1)
The talk of "before/after" the iteration of a loop is only meaningful if the pre/post inc/decrement occurs in the condition. More often, it'll be in the continuation clause, where it can't change any logic, albeit it might be slower for class types to use postfix and people should not use that without reason.Leitmotif
G
1

You asked for an example:

This (order is a std::vector) will crash for i == order.size()-1 on the order[i].size() access:

while(i++ < order.size() && order[i].size() > currLvl);

This will not crash at order[i].size(), as i will be incremented, checked and the loop will be exited:

while(++i < order.size() && order[i].size() > currLvl);
Goethe answered 19/3, 2021 at 20:59 Comment(0)
D
0

Understanding the language syntax is important when considering clarity of code. Consider copying a character string, for example with post-increment:

char a[256] = "Hello world!";
char b[256];
int i = 0;
do {
  b[i] = a[i];
} while (a[i++]);

We want the loop to execute through encountering the zero character (which tests false) at the end of the string. That requires testing the value pre-increment and also incrementing the index. But not necessarily in that order - a way to code this with the pre-increment would be:

int i = -1;
do {
  ++i;
  b[i] = a[i];
} while (a[i]);

It is a matter of taste which is clearer and if the machine has a handfull of registers both should have identical execution time, even if a[i] is a function that is expensive or has side-effects. A significant difference might be the exit value of the index.

Dithyramb answered 2/11, 2014 at 16:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.