22

Are variables that are created inside a while or for loop disposed/deleted from memory after the loop is done executing? also, is it a bad coding habit to create temporary variables inside a loop?

in this example, does it create 100 X variables and then dispose of them, or are they disposed on each iteration? thanks. example:

int cc =0;
while(cc < 100){
    int X = 99; // <-- this variable
    cc++;    
}
Daniel Valland
  • 1,057
  • 4
  • 21
  • 45
  • 4
    "Disposed" in relation to an `int` variable/value is .. not very exciting as no special cleanup/destruction is performed. The only thing of interest in this case is the *visibility/scope* of the variable. – user2864740 Oct 24 '14 at 21:23
  • There's just one variable. And it is not unlikely there's none at all, the optimizer may well store the value in a CPU register. There's no special cleanup, it just "forgets" the variable when it restores the stack pointer. Important, *int* has to be fast. Best thing to do to get insight is looking at the assembly listing that your compiler can generate. – Hans Passant Oct 24 '14 at 21:30
  • Disposed, in combination with C++, is a rather problematic term. It could mean "destroyed", but then you should write "destroyed" and not "disposed". Or it could mean something else. In your question "something else" might be: does the compiler generate code that repeatedly allocates and deallocates storage for the variable. – Paul Groke Oct 24 '14 at 21:36

8 Answers8

33

Scope and lifetime are two different things. For variables defined at block scope without static, they're more or less tightly linked, but they're still distinct concepts -- and you can shoot yourself in the foot if you don't keep them straight.

Quoting the snippet from the question:

int cc =0;
while(cc < 100){
    int X = 99; // <-- this variable
    cc++;    
}

The scope of X is the region of program text in which its name is visible. It extends from the point at which it's defined to the end of the enclosing block, which is delimited by the { and } characters. (The fact that the block happens to be part of a while statement is not directly relevant; it's the block itself that defines the scope.)

Inside the block, the name X refers to that int variable. Outside the block, the name X is not visible.

The lifetime of X is the time during program execution when X logically exists. It begins when execution reaches the opening { (before the definition), and ends when execution reaches the closing }. If the block is executed 100 times, then X is created and "destroyed" 100 times, and has 100 disjoint lifetimes.

Although the name X is visible only within its scope, the object called X may be accessed (directly or indirectly) any time within its lifetime. For example, if we pass &X to a function, then that function may read and update the object, even though the function is completely outside its scope.

You can take the address of X, and save that address for use after its lifetime has ended -- but doing so causes undefined behavior. A pointer to an object whose lifetime has ended is indeterminate, and any attempt to dereference it -- or even to refer to the pointer's value -- has undefined behavior.

Nothing in particular actually has to happen when an object reaches the end of its lifetime. The language just requires the object to exist during its lifetime; outside that, all bets are off. The stack space allocated to hold the object might be deallocated (which typically just means moving the stack pointer), or, as an optimization, the stack space might remain allocated and re-used for the next iteration of the loop.

Also, is it a bad coding habit to create temporary variables inside a loop?

Not at all. As long as you don't save the object's address past the end of its lifetime, there's nothing wrong with it. The allocation and deallocation will very often be done on entry to and exit from the function rather than the block, as a performance optimization. Restricting variables to a reasonably tight scope is a very good coding habit. It makes the code easier to understand by restricting unnecessary interactions between different parts of the code. If X is defined inside the body of the loop, nothing outside the loop can affect it (if you haven't done something too tricky), which makes it easier to reason about the code.

UPDATE: If X were of a type with a non-trivial constructor and/or destructor, creating and destruction of X actually has to be performed on entry to and exit from the block (unless the compiler is able to optimize that code away). For an object of type int, that isn't an issue.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
9

Yes, the variable is created and destroyed N times, unless the compiler optimizes it somehow (which it can, I believe). It's not a very big deal when you have just one int though. It becomes more problematic when you have some complex object recreated 99 times inside your loop.

A small practical example:

#include <iostream>
using namespace std;

class TestClass
{
public:
    TestClass();
    ~TestClass();
};
TestClass::TestClass()
{
    cout<<"Created."<<endl;
}

TestClass::~TestClass()
{
    cout<<"Destroyed"<<endl;
}

int main() {
    for (int i = 0; i < 5; ++i)
    {
        TestClass c;
    }
    return 0;
}

In this code TestClass c will be recreated 5 times. IdeOne Demo.

FreeNickname
  • 7,398
  • 2
  • 30
  • 60
6

Yes. Any variable defined within a scope { }:

if (true) { // Forgive me father for this heresy :)
    int a = 0;
}
a = 1; // This will throw an error

Is automatically deallocated once it goes out of scope.

This is also true in this case:

for (int i = 0; i < 10; ++i) {
    // Do stuff
    ...
}
i = 1; // This will throw an error

The scope of i is limited to the for loop, even if it was not declared inside a pair of { }.

JoErNanO
  • 2,458
  • 1
  • 25
  • 27
2

As pointed out before, in truth there's no need no create/destroy a local variable repeatedly.

That's an unnecessary waste of CPU time.

Example, compiled with "gcc -S -masm=intel -fverbose-asm"

int crazyloop (int n) {
  if (n > 0) {
      int i;
      for (i = 0; i < n; i++)
         ;
  }
  return n;
}

the corresponding assembly listing is:

_Z9crazyloopi:
.LFB0:
    .cfi_startproc
    push    rbp #
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    mov rbp, rsp    #,
    .cfi_def_cfa_register 6
    mov DWORD PTR [rbp-20], edi # n, n
    cmp DWORD PTR [rbp-20], 0   # n,
    jle .L2 #,
    mov DWORD PTR [rbp-4], 0    # i,
.L4:
    mov eax, DWORD PTR [rbp-4]  # tmp89, i
    cmp eax, DWORD PTR [rbp-20] # tmp89, n
    jge .L2 #,
    add DWORD PTR [rbp-4], 1    # i,
    jmp .L4 #
.L2:
    mov eax, DWORD PTR [rbp-20] # D.3136, n
    pop rbp #
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

The interesting part lies in the references to register RBP. Once set, it does not change. Variable "i" is always at [rbp-4]. (Variations of the code, with more vars, etc., gave the same results = there's no repeated allocation/deallocation = modifications to the stack top position).

It is the most sensible thing to do: think of a loop that iterates trillions of times.

Would another compiler do it differently? Possibly yes, but, why on earth it would do that?

Security might be a concern? Unlikely; in that case the programmer should simply overwrite a variable before letting it vanish.

1

Yes

If you want to have access to the variable after the loop you should declare it ouside of the loop

while(...) {
    int i = 0;
    i++; // valid
}
i++; // invalid, i doesnt exist in this context

i outside of the loop

int i = 0;
while(...) {
    i++; // valid
}
i++; // valid

the lifespan of a viariable is limited to the context {...} in which it was created Is we where considering an object, the destructor would be called when reaching }

Amxx
  • 3,020
  • 2
  • 24
  • 45
0

Yes, they are destroyed when they go out of scope. Note that this isn't specific to variables in the loop. This rule applies to all variables with automatic storage duration.

Pradhan
  • 16,391
  • 3
  • 44
  • 59
0

Any variable remain active within it's scope. Outside the scope that particular variable even doesn't exits, forget about accessing its value.

for(;;)
{
    int var;  // Scope of this variable is within this for loop only.
}
// Outside this for loop variable `var` doesn't exits.
Shravan40
  • 8,922
  • 6
  • 28
  • 48
0

The variables declared inside will have their own scope. you can use it when you know that you will not use that variabel outside of the scope. That's compiler job. :)

lappet
  • 116
  • 1
  • 7