2

I need the opinion of stack overflow to settle something that has been sitting in the back of my head about for loop efficiency. Now, when I began programming, "getting it to work" was a big priority and most of my for loops looked like this.

for (int i = 0; i < N; i++) {;}

Then I was tought, especially with C++ development that pre-increment saves you some calls, and considering that would be N calls and it doesn't alter the readability I got into the habit of.

for (int i = 0; i < N; ++i) {;}

This was good enough for a while, but focusing on the readability, and after reading some of Code Complete by Steve McConnell, I arrived at this.

for (int loop_index = 0; loop_index < loop_count; ++loop_index) {;}

And these variables change based on the context of the code. Then I read some of Effective C++ about built in types constructors and assignment. And basically that the difference between

int i = 42;

and

int i(42); 

Is that the former one calls the constructor and the assignment operator while the latter only the constructor. So I got that into my routine whilst coding. So my question, is this the most efficient and readable way of writing a for loop:

for (int loop_index(0); loop_index < loop_counter; ++loop_index) {;}
2
  • 10
    You don't need opinions on matters of efficiency, you need cold hard facts. That of course, is my opinion. But people seem to love to waste time in data-free arguments on topics amenable to quantitative analysis here on SO, so don't let me stop you engaging in the practice. Commented Aug 8, 2012 at 13:36
  • 2
    For int, neither of these issues make any difference, and in practice copy-elision means that copy- vs. direct-initialisation is almost never a concern even for complicated types. Pre-increment is a good habit, since it can occasionally be more efficient, without affecting readibility. Long vs. short variable names are purely a matter of taste; personally, I find i easier to read than loop_index, but others will disagree. Commented Aug 8, 2012 at 13:45

6 Answers 6

5

Actually,

for (int i = 0; i < N; i++) {;}

is fine. i is an int, so the compiler will optimise the post-increment away anyway. Whether you initialise an int with int i(42); or with int i = 42; is also a question of taste.

I would also call the iterator i, instead of loop_index. The former is ubiquitously understood, while the latter is strange.

If you are dealing with iterators, however, the picture changes. Chances are it++ will still be optimised to ++it, but here, I'd rather use pre-increment.

Sign up to request clarification or add additional context in comments.

Comments

2

First of all, your last point is not correct. This line

int i = 42;

does copy initialization (see this related GoTW). There is no assignment there. For assignment you would need

int i;
i = 42;

Second, when dealing with builtins such as integer types, there will probably be no difference in the code produced by the compiler. You should profile the different options and see.

Comments

2

If you're not using iterators, it shouldn't matter, because compiler will translate this to the same code.

Addendum: If you're using iterators:

for(vector<int>::iterator i = a.begin(); i != a.end(); ++i)

Then ++i is i.operator++() and i++ is i.operator++(int) which can mean two different things.

BTW. You can measure performance if this is a problem.

Comments

1

If you're using built in types, or most iterators, all of these will compile to the same code.

So I'd stick with the one that is most idiomatic to C++.

for (int i = 0; i < N; ++i) {;}

or if you want to be wordy ( but i and k are traditionally loop indices )

for (int loop_index = 0; loop_index < loop_count; ++loop_index) {;}

As evidence for my initial claim: These two pieces of code generate identical assembly code. ( g++ 4.0.1 on OS X compiled with g++ -Os -S test.cpp)

void f(int); // So that smart compilers can't optimise away the loop entirely.

void g()
{
  int N=100;
  // for( int i=0; i<N; i++)
  for (int i(0); i < N; ++i) 
  {
    f(i);
  }
}

For completeness, the generated code is:

.globl __Z1gv
__Z1gv:
LFB2:
    pushl   %ebp
LCFI0:
    movl    %esp, %ebp
LCFI1:
    pushl   %esi
LCFI2:
    xorl    %esi, %esi
    subl    $20, %esp
LCFI3:
L2:
    movl    %esi, (%esp)
    incl    %esi
    call    L__Z1fi$stub
    cmpl    $100, %esi
    jne L2
    addl    $20, %esp
    popl    %esi
    leave
    ret

3 Comments

So there is no gain in having i(0) instead of i=0 ?
Constructor taking single argument is called no matter if you write T x(a) or T x = a
@tomasgudm you really can't have two translation to assembly when i is an int.
0

While others have covered post- vs pre-increments and initializations quite well, I'd like to add that using int i in most cases is more readable than int loop_index, because that's what everyone else is using and expecting.

The only cases when you may want to call it something else is when you have multiple loops, and complicated interactions between the loop indexes. For example

for (int row = 0; row < rows; row++) {
    for (int column = 0; column < columns; column++) {
        stuff[row * columns + column] = calc_stuff(row, column);
    }
}

1 Comment

When dealing with matrices, row and column is probably a good idea. Otherwise, I'd stick with i,j,k.
0

Efficient? No, it most likely will be the same, as most compilers will optimize that post increment and initialization for int and simple pointers. And as to whether loop_index is more readable than i, IMO, it's less readable for simple counters.

If it's an iterator though, it's different story, compilers can't always optimize overloaded post increment or double initialization of iterators. I also prefer using the iterated object's names for iterator, as that reflects what's being used better, using the object's name looks more natural when using the arrow -> operator to dereference the iterator.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.