20

My instructor once told me that I should not define a variable inside a loop, but I honestly still do not understand why.

What are the disadvantages of that?

Could any body explain that to me?

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
Mo Haidar
  • 507
  • 2
  • 4
  • 9
  • 10
    What programming language was your instructor teaching? – Brian Sep 08 '15 at 14:35
  • c++ programming language – Mo Haidar Sep 08 '15 at 14:35
  • 2
    If you define a variable with a non-primitive type in a loop, your program might end up needlessly calling its constructor every time through the loop. If you only need to define it once outside the loop, do that. – Brandin Sep 08 '15 at 14:41
  • 19
    When you have such confusion about what an instructor says, the best resource is asking the instructor. They can give you the dense back and forth communication that a Q&A site cannot provide. –  Sep 08 '15 at 14:54
  • 1
    Cross-site duplicate: *[Difference between declaring variables before or in loop?](http://stackoverflow.com/questions/407255)* (and of course many, many duplicates on that site for such an elementary question (including the ones that are only about C++)). – Peter Mortensen Sep 08 '15 at 19:49
  • 2
    That advice was specific to a context. As a matter of personal style, I prefer to declare my variables `const` unless there’s a reason not to (a habit from functional programming). Either I won’t modify them, and the optimizer should detect when they aren’t needed, or I will and I’ve prevented a serious bug. When those constant intermediate values are specific to an iteration of the loop, that means declaring them inside the loop. Another time when you need to declare variables outside the loop, though, is when you’ll refer to them outside the loop; for example, the results you’re storing. – Davislor Sep 08 '15 at 20:38

3 Answers3

47

It's not a problem to define a variable within a loop. In fact, it's good practice, since identifiers should be confined to the smallest possible scope.

What's bad is to assign a variable within a loop if you could just as well assign it once before the loop runs. Depending on how complex the right-hand side of the assignment is, this could become rather expensive and might even dominate the run time of the loop. If you write a loop that uses the same computed value in all iterations, you should definitely compute it above the loop - that is more important than minimizing its scope.

To clarify: as long as compute() always returns the same value, this

int value = compute();
while (something) {
    doSomething(value);
}

is smarter than this:

while (something) {
    int value = compute();
    doSomething(value);
}
Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
  • 2
    How would you define a variable in the loop and assign it before the loop? – Masked Man Sep 08 '15 at 16:27
  • 6
    @MaskedMan, I think you're misunderstanding. What Kilian meant is if you have a variable that is assigned the same value during each iteration of a loop, e.g., the same date variable is set to `1/1/1900`, the variable should be declared and the value should be assigned prior to the loop. – ps2goat Sep 08 '15 at 16:36
  • 2
    I don't think there's been a compiler written in the last twenty years (outside of an undergrad compiler course) that wouldn't figure out you're assigning the same value on each iteration and move that assignment out of the loop. – TMN Sep 08 '15 at 18:41
  • 15
    @tmn: Never let a compiler do what you can trivially do yourself with greater code clarity. – Robert Harvey Sep 08 '15 at 19:09
  • 10
    @TMN, not necessarily. That optimization is only possible if the compiler can prove that the computation is side-effect free. – Paul Draper Sep 08 '15 at 19:26
  • @ps2goat No, I get that point. My question still remains the same. It is a good practice to define the variable in the loop, which I also agree with. But how would you do it if you want to assign it before the loop? Does it mean if the variable is loop invariant, define and assign it before the loop, and if it is not, then define it within the loop? – Masked Man Sep 09 '15 at 01:59
  • @MaskedMan, it depends. If it is synchronous code and the variable is always assigned data within the loop, I'd declare it outside the loop (initialize it to null) and assign the values within the loop. If it's asynchronous, such as using `ParallelFor()` with LINQ, I declare the variable within the loop to prevent overwriting the variable declared outside the loop. – ps2goat Sep 09 '15 at 04:29
  • 1
    @RobertHarvey: True, but which code is clearer: the single assignment, or the scope restriction? I'd argue that placing the declaration (and assignment) inside the loop shows intent, which is more valuable than explicitly optimizing the loop. – TMN Sep 09 '15 at 14:29
  • 1
    @TMN: You intend to create a new variable *every loop,* only to have the compiler optimize it away? If you're going to do that, at least acknowledge that the real reason to do it is to *confine the scope of the variable to the inside of the loop.* – Robert Harvey Sep 09 '15 at 14:46
  • 1
    @TMN: On the contrary, this spreads disinformation. A new developer reading this code will assume that `doSomething()` has an influence on the return value of `compute()`, thus implying that this computed value is not a fixed value (in scope of the iteration). – Flater Jan 10 '19 at 07:24
21

Complex types have non-trivial constructors and destructors.

Those will get called at the start and end of the loop body (as it's initialized and goes out of scope). If the initialization is expensive like it needs to allocate some memory then that should be avoided.

However for trivial types that is no problem. The allocation and deallocation itself is just adding and subtracting a value from the stack pointer. (which will get optimized out)

ratchet freak
  • 25,706
  • 2
  • 62
  • 97
  • thanks, exactly the answer I was looking for! – gebbissimo Jun 25 '19 at 15:52
  • There is no problem, but I don't see a reason for doing that extra thing (adding and subtracting a value from the stack pointer) and letting the compile do optimization if we just can declare the variable outside the loop. – Andreas K. Jun 19 '20 at 10:14
7

Well, his advice is slightly too simple (that's an understatement).
Following it ranges all the way from a good idea over who cares and bad idea to impossible.

  1. You should follow it whenever re-using is cheaper than destroying the old and creating a new one.

    #include <iostream>
    #include <string>
    
    int main() {
        std::string s; // Don't needlessly free the buffer
        while ((std::cin >> s))
            std::cout << s;
    }
    
  2. You should shun it as a matter of style when it doesn't matter for performance.

    #include <stdio.h>
    #include <stdlib.h>
    int f(int, int);
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            int x = rand(); // Declared here so you don't need to hunt it down.
            printf("%d => %d\n", x, f(x-1, x+i));
        }
    }
    
  3. You really should shun it when it has worse performance or the wrong semantics.

    #include <iostream>
    #include <string>
    std::string generate(int);
    
    int main() {
        for(int i = 0; i < 100; ++i) {
            std::string s = generate(i); // Using copy-ellision here
            std::cout << s;
        }
    }
    
  4. You cannot follow it when the used type allows neither swapping, nor move-assignment nor copy-assignment.

    #include <iostream>
    #include <puzzle>
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            Puzzle x(i); // Puzzle is an immutable class. For whatever reasons.
            std::cout << x;
        }
    }
    
Deduplicator
  • 8,591
  • 5
  • 31
  • 50
  • 3
    Depending on your definition of "in a loop", 1 can be changed to `for (std::string s; std::cin >> s;) ...` and still be "outside" – Caleth Feb 16 '18 at 10:04