Is there any overhead to declaring a variable within a loop? (C++)

C++LoopsVariable Declaration

C++ Problem Overview


I am just wondering if there would be any loss of speed or efficiency if you did something like this:

int i = 0;
while(i < 100)
{
    int var = 4;
    i++;
}

which declares int var one hundred times. It seems to me like there would be, but I'm not sure. would it be more practical/faster to do this instead:

int i = 0;
int var;
while(i < 100)
{
    var = 4;
    i++;
}

or are they the same, speedwise and efficiency-wise?

C++ Solutions


Solution 1 - C++

Stack space for local variables is usually allocated in function scope. So no stack pointer adjustment happens inside the loop, just assigning 4 to var. Therefore these two snippets have the same overhead.

Solution 2 - C++

For primitive types and POD types, it makes no difference. The compiler will allocate the stack space for the variable at the beginning of the function and deallocate it when the function returns in both cases.

For non-POD class types that have non-trivial constructors, it WILL make a difference -- in that case, putting the variable outside the loop will only call the constructor and destructor once and the assignment operator each iteration, whereas putting it inside the loop will call the constructor and destructor for every iteration of the loop. Depending on what the class' constructor, destructor, and assignment operator do, this may or may not be desirable.

Solution 3 - C++

They are both the same, and here's how you can find out, by looking at what the compiler does (even without optimisation set to high):

Look at what the compiler (gcc 4.0) does to your simple examples:

1.c:

main(){ int var; while(int i < 100) { var = 4; } }

gcc -S 1.c

1.s:

_main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	movl	$0, -16(%ebp)
	jmp	L2
L3:
	movl	$4, -12(%ebp)
L2:
	cmpl	$99, -16(%ebp)
	jle	L3
	leave
	ret

2.c

main() { while(int i < 100) { int var = 4; } }

gcc -S 2.c

2.s:

_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    $0, -16(%ebp)
        jmp     L2
L3:
        movl    $4, -12(%ebp)
L2:
        cmpl    $99, -16(%ebp)
        jle     L3
        leave
        ret

From these, you can see two things: firstly, the code is the same in both.

Secondly, the storage for var is allocated outside the loop:

         subl    $24, %esp

And finally the only thing in the loop is the assignment and condition check:

L3:
        movl    $4, -12(%ebp)
L2:
        cmpl    $99, -16(%ebp)
        jle     L3

Which is about as efficient as you can be without removing the loop entirely.

Solution 4 - C++

These days it is better to declare it inside the loop unless it is a constant as the compiler will be able to better optimize the code (reducing variable scope).

EDIT: This answer is mostly obsolete now. With the rise of post-classical compilers, the cases where the compiler can't figure it out are getting rare. I can still construct them but most people would classify the construction as bad code.

Solution 5 - C++

Most modern compilers will optimize this for you. That being said I would use your first example as I find it more readable.

Solution 6 - C++

For a built-in type there will likely be no difference between the 2 styles (probably right down to the generated code).

However, if the variable is a class with a non-trivial constructor/destructor there could well be a major difference in runtime cost. I'd generally scope the variable to inside the loop (to keep the scope as small as possible), but if that turns out to have a perf impact I'd look to moving the class variable outside the loop's scope. However, doing that needs some additional analysis as the semantics of the ode path may change, so this can only be done if the sematics permit it.

An RAII class might need this behavior. For example, a class that manages file access lifetime might need to be created and destroyed on each loop iteration to manage the file access properly.

Suppose you have a LockMgr class that acquires a critical section when it's constructed and releases it when destroyed:

while (i< 100) {
    LockMgr lock( myCriticalSection); // acquires a critical section at start of
                                      //    each loop iteration
    
    // do stuff...
    
}   // critical section is released at end of each loop iteration

is quite different from:

LockMgr lock( myCriticalSection);
while (i< 100) {

    // do stuff...
    
}

Solution 7 - C++

Both loops have the same efficiency. They will both take an infinite amount of time :) It may be a good idea to increment i inside the loops.

Solution 8 - C++

I once ran some perfomance tests, and to my surprise, found that case 1 was actually faster! I suppose this may be because declaring the variable inside the loop reduces its scope, so it gets free'd earlier. However, that was a long time ago, on a very old compiler. Im sure modern compilers do a better job of optimizing away the diferences, but it still doesn't hurt to keep your variable scope as short as possible.

Solution 9 - C++

#include <stdio.h>
int main()
{
    for(int i = 0; i < 10; i++)
    {
        int test;
        if(i == 0)
            test = 100;
        printf("%d\n", test);
    }
}

Code above always prints 100 10 times which means local variable inside loop is only allocated once per each function call.

Solution 10 - C++

The only way to be sure is to time them. But the difference, if there is one, will be microscopic, so you will need a mighty big timing loop.

More to the point, the first one is better style because it initializes the variable var, while the other one leaves it uninitialized. This and the guideline that one should define variables as near to their point of use as possible, means that the first form should normally be preferred.

Solution 11 - C++

With only two variables, the compiler will likely be assign a register for both. These registers are there anyway, so this doesn't take time. There are 2 register write and one register read instruction in either case.

Solution 12 - C++

I think that most answers are missing a major point to consider which is: "Is it clear" and obviously by all the discussion the fact is; no it is not. I'd suggest in most loop code the efficiency is pretty much a non-issue (unless you calculating for a mars lander), so really the only question is what looks more sensible and readable & maintainable - in this case I'd recommend declaring the variable up front & outside the loop - this simply makes it clearer. Then people like you & I would not even bother to waste time checking online to see if it's valid or not.

Solution 13 - C++

thats not true there is overhead however its neglect able overhead.

Even though probably they will end up at same place on stack It still assigns it. It will assign memory location on stack for that int and then free it at the end of }. Not in heap free sense in sense it will move sp (stack pointer) by 1. And in your case considering it only has one local variable it will just simply equate fp(frame pointer) and sp

Short answer would be: DONT CARE EITHER WAY WORKS ALMOST THE SAME.

But try reading more on how stack is organized. My undergrad school had pretty good lectures on that If you wanna read more check here http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Assembler1/lecture.html

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser98188View Question on Stackoverflow
Solution 1 - C++laaltoView Answer on Stackoverflow
Solution 2 - C++Adam RosenfieldView Answer on Stackoverflow
Solution 3 - C++Alex BrownView Answer on Stackoverflow
Solution 4 - C++JoshuaView Answer on Stackoverflow
Solution 5 - C++Andrew HareView Answer on Stackoverflow
Solution 6 - C++Michael BurrView Answer on Stackoverflow
Solution 7 - C++Larry WatanabeView Answer on Stackoverflow
Solution 8 - C++user3864776View Answer on Stackoverflow
Solution 9 - C++Byeonggon LeeView Answer on Stackoverflow
Solution 10 - C++anonView Answer on Stackoverflow
Solution 11 - C++MSaltersView Answer on Stackoverflow
Solution 12 - C++RobView Answer on Stackoverflow
Solution 13 - C++grobartnView Answer on Stackoverflow