Jump to content
  • Advertisement
Sign in to follow this  
cozzie

pre-increment versus post-increment

This topic is 565 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 all,

I'm reading Game Engine Architecture and stumbled upon the topic 'pre-' versus 'post-increment' in for loops.

I.e.:

 

++i (pre)

i++ (post)

 

From 'the old days' I remember that I've switched from post to pre, always. At that time is was something about (premature) optimization I recall.

But in the book it says it's better to have post, because 'pre' gives a data dependency, CPU must wait for increment to e completed before it's value can be used in the expression. The book also says thay most compilers will solve it in the background anyway.

 

Just out of curiosity, what do you do?

Share this post


Link to post
Share on other sites
Advertisement
Just out of curiosity, what do you do?

 

Since this is curiosity rather than anything backed by facts. I always go for i++ unless I specifically need the pre-version. For loops I don't think I have ever used ++i. I use the post version simply because it was the first increment operator I saw/learned and it does the job. I did read a post recently mentioning the pre version and also commenting that the benefit of it no longer applies. How much truth is in that I cannot say. Compilers do tend to be very smart now.

Edited by Nanoha

Share this post


Link to post
Share on other sites

How is i++ algorithmically more complex than ++i?

If I am not mistaken, they both lead to the same thing when compiled, right?
They should only be two operations. An "ADD" and a "SET"

Edited by Tangletail

Share this post


Link to post
Share on other sites

Hi all,

I'm reading Game Engine Architecture and stumbled upon the topic 'pre-' versus 'post-increment' in for loops.

I.e.:

 

++i (pre)

i++ (post)

 

From 'the old days' I remember that I've switched from post to pre, always. At that time is was something about (premature) optimization I recall.

But in the book it says it's better to have post, because 'pre' gives a data dependency, CPU must wait for increment to e completed before it's value can be used in the expression. The book also says thay most compilers will solve it in the background anyway.

 

Just out of curiosity, what do you do?

I use pre by default for the reasons Hodgman described.

 

With regards to data dependency, it only applies if the result of the increment is used. So using increment at the end of a for loop does not use the result in an expression so there is no data dependency difference. However, if you are using the result of the operator, the the point is marginally valid. However I still don't find it too compelling for the following reasons: 1)the choice between pre and post increment can effect the readability of the algorithm, so this micro-optimization is less important than those considerations. 2) Rewriting code to avoid the use of preincrement may not actually reduce data dependency because the data dependency can be unavoidable. For example, moving a pre-increment to it's own line and making it a post increment does not reduce data dependency.

 

I'd say that avoiding data dependency is a good idea in designing algorithms in general but using post increment more misses the mark.

Share this post


Link to post
Share on other sites

I use pre because it's algorithmically simpler. In the case of for loops using iterator types instead of integers, for(...; i++) is much more complex than for(...; ++i) (and IMHO - wrong) and often the compiler won't be able to fix that mistake for you, depending on how complex the iterator type is / what your optimization level is.

On the other hand, in the integer for loop case, the compiler is smart enough to switch between i++ and ++i versions in the background for you.
So IMHO, in C/C#/etc, i++ is more typical, but in C++ ++i is the right default.

The difference between the two operations is that post will return the previous value of the variable you increment when assigning to a variable. In the case of user types, like iterators, this can come with a copy cost and as such the rule started to exist that you should prefer per-increment for a loop variable.

When user types are involved the compiler cannot see the optimisations anymore that it can do for POD types, most likely a ++i and i++ will both result in to a inc eax assembly instruction in the case of a for loop. But when its implemented as an overloaded operator the compiler has to insert that code there.

As a simple example this code with a release compile on VS2015:

int i = 0;
int y = ++i;
int x = i++;
//can be a fair amount of code in between here
std::cout << i << x << y;

Will generate this assembly:

00007FF6718C9C43  mov         edx,2  
00007FF6718C9C48  mov         rcx,qword ptr [__imp_std::cout (07FF6718CD1C0h)]  
00007FF6718C9C4F  call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6718CD198h)] 
00007FF6718C9C55  mov         rcx,rax  
00007FF6718C9C58  mov         edx,1  
00007FF6718C9C5D  call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6718CD198h)]  
00007FF6718C9C63  mov         rcx,rax  
00007FF6718C9C66  mov         edx,1  
00007FF6718C9C6B  call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6718CD198h)]

Which shows that for integers the compiler can compile the increment away completely. When you wrap that code in a for loop you get a sub asm call followed by a jne on the counter value to jump back to the beginning of the loop.

Share this post


Link to post
Share on other sites
Thanks guys.
I'll stick with the ++i like I've gotten used to.

To de honest, I think that almost every for loop I use is either an (u)int, size_t or some container's iterator.

Share this post


Link to post
Share on other sites

Depends on your goal. I see very little post increment usages just for the sake of the "post". So in my opionion it's because of conventions in writing. Loops are written with post incremeant, giving us an habit of writing it in that way (for i=0;i<10;i++).

But when you do need to evaluate the value before incremeanting ( var x = i++) So you both save the previous value and incremeant it at the same time, then you use it.

 

From readablity perspective it's nonsense to use that. because the purpose of var x=i++ is to assign i to x, the i++ is a side effect although we've directly written it to do it. It's 2 logical operations inside 1 sentence, which is basicly a smelly code to write (like a function with 2 responsibilities).

 

What was shown above is compiler optimizations. If you provide constant values and do some math with them, it'll simply calculate in compile team.

So (1+2+3+4+5) ++ becomes  16.

It's true with many mathematical operations. The really interesting optimizations are inside the CPU where conditions have to be met.

For example ++i > 5 , How does the cpu know which code to load? The one that ++i > 5 is true or the one that it's smaller? 

if i is known as a const, it will produce the value of 6 , then 6>5 is always true. So it would never load the 'else' code.

But if it's a runtime variable, it would sometimes guess wrong (small cases) and will load both code into the cache. 

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!