É bom definir uma variável dentro de um loop? [fechadas]

15

Meu instrutor me disse uma vez que eu não deveria definir uma variável dentro de um loop , mas sinceramente ainda não entendo o porquê.

Quais são as desvantagens disso?

Alguém poderia me explicar isso?

user3260672
fonte
7
Qual linguagem de programação o seu instrutor ensinava?
Brian
2
Se você definir uma variável com um tipo não primitivo em um loop, seu programa poderá acabar desnecessariamente chamando seu construtor todas as vezes através do loop. Se você precisar defini-lo apenas uma vez fora do loop, faça isso.
Brandin
17
Quando você tem tanta confusão sobre o que um instrutor diz, o melhor recurso é perguntar ao instrutor. Eles podem fornecer uma comunicação densa e inversa que um site de perguntas e respostas não pode fornecer.
1
Duplicação entre sites: diferença entre declarar variáveis ​​antes ou no loop? (e, é claro, muitas duplicatas nesse site para uma pergunta tão elementar (incluindo as que são apenas sobre C ++)).
Peter Mortensen
2
Esse conselho foi específico para um contexto. Por uma questão de estilo pessoal, prefiro declarar minhas variáveis, a constmenos que haja uma razão para não (um hábito da programação funcional). Ou não vou modificá-los, e o otimizador deve detectar quando não são necessários, ou eu irei e evitei um bug sério. Quando esses valores intermediários constantes são específicos para uma iteração do loop, isso significa declará-los dentro do loop. Outro momento em que você precisa declarar variáveis ​​fora do loop, porém, é quando você se refere a elas fora do loop; por exemplo, os resultados que você está armazenando.
Davislor 8/09/15

Respostas:

42

Não é um problema definir uma variável dentro de um loop. De fato, é uma boa prática, pois os identificadores devem ser confinados ao menor escopo possível.

O que é ruim é atribuir uma variável a um loop se você puder atribuí-lo uma vez antes de o loop ser executado. Dependendo da complexidade do lado direito da tarefa, isso pode se tornar bastante caro e até dominar o tempo de execução do loop. Se você escreve um loop que usa o mesmo valor calculado em todas as iterações, definitivamente deve computá-lo acima do loop - isso é mais importante do que minimizar seu escopo.

Para esclarecer: desde que compute()sempre retorne o mesmo valor, isso

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

é mais inteligente que isso:

while (something) {
    int value = compute();
    doSomething(value);
}
Kilian Foth
fonte
2
Como você definiria uma variável no loop e a atribuiria antes do loop?
Masked Man
6
@ MaskedMan, acho que você está entendendo mal. O que Kilian quis dizer é que se você tem uma variável que recebe o mesmo valor durante cada iteração de um loop, por exemplo, a mesma variável de data é definida como 1/1/1900, a variável deve ser declarada e o valor deve ser atribuído antes do loop.
Ps2goat 8/09/2015
2
Eu não acho que tenha havido um compilador escrito nos últimos vinte anos (fora de um curso de compilador de graduação) que não descobriria que você está atribuindo o mesmo valor em cada iteração e moveria essa tarefa para fora do loop.
TMN
14
@tmn: nunca deixe um compilador fazer o que você pode fazer trivialmente com maior clareza de código.
Robert Harvey
10
@TMN, não necessariamente. Essa otimização só é possível se o compilador puder provar que a computação é livre de efeitos colaterais.
Paul Draper
16

Tipos complexos têm construtores e destruidores não triviais.

Esses serão chamados no início e no final do corpo do loop (como é inicializado e sai do escopo). Se a inicialização for cara, como ela precisa alocar memória, isso deve ser evitado.

No entanto, para tipos triviais, isso não é problema. A própria alocação e desalocação está apenas adicionando e subtraindo um valor do ponteiro da pilha. (que será otimizado)

catraca arrepiante
fonte
obrigado, exatamente a resposta que eu estava procurando!
Gbbissimo
6

Bem, o conselho dele é um pouco simples demais (isso é um eufemismo).
A sequência abrange desde uma boa ideia sobre quem se importa e uma má ideia até impossível .

  1. Você deve segui-lo sempre que a reutilização for mais barata do que destruir o antigo e criar um novo.

    #include <iostream>
    #include <string>
    
    int main() {
        std::string s; // Don't needlessly free the buffer
        while ((std::cin >> s))
            std::cout << s;
    }
  2. Você deve evitá-lo por uma questão de estilo quando não importa para o desempenho.

    #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. Você realmente deve evitá-lo quando tiver um desempenho pior ou a semântica errada.

    #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. Você não pode segui-lo quando o tipo usado não permite troca, nem atribuição de movimento nem atribuição de cópia.

    #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;
        }
    }
Desduplicador
fonte
2
Dependendo da sua definição de "em um loop", 1 pode ser alterado para for (std::string s; std::cin >> s;) ...e ainda ser "fora"
Caleth