¿Es bueno definir una variable dentro de un bucle? [cerrado]

15

Mi instructor una vez me dijo que no debería definir una variable dentro de un ciclo , pero honestamente todavía no entiendo por qué.

¿Cuáles son las desventajas de eso?

¿Podría alguien explicarme eso?

usuario3260672
fuente
77
¿Qué lenguaje de programación estaba enseñando tu instructor?
Brian
2
Si define una variable con un tipo no primitivo en un bucle, su programa podría terminar invocando innecesariamente a su constructor cada vez a través del bucle. Si solo necesita definirlo una vez fuera del ciclo, hágalo.
Brandin
17
Cuando tienes tanta confusión sobre lo que dice un instructor, el mejor recurso es preguntarle al instructor. Pueden brindarle una comunicación densa de ida y vuelta que un sitio de preguntas y respuestas no puede proporcionar.
1
Duplicado entre sitios: ¿ diferencia entre declarar variables antes o en bucle? (y, por supuesto, muchos, muchos duplicados en ese sitio para una pregunta tan elemental (incluidas las que solo tratan sobre C ++)).
Peter Mortensen
2
Ese consejo era específico de un contexto. Como cuestión de estilo personal, prefiero declarar mis variables a constmenos que haya una razón para no hacerlo (un hábito de la programación funcional). O no los modificaré, y el optimizador debería detectar cuándo no son necesarios, o lo haré y he evitado un error grave. Cuando esos valores intermedios constantes son específicos de una iteración del bucle, eso significa declararlos dentro del bucle. Sin embargo, otro momento en el que necesita declarar variables fuera del ciclo es cuando se referirá a ellas fuera del ciclo; por ejemplo, los resultados que está almacenando.
Davislor

Respuestas:

42

No es un problema definir una variable dentro de un bucle. De hecho, es una buena práctica, ya que los identificadores deben limitarse al alcance más pequeño posible.

Lo que es malo es asignar una variable dentro de un bucle si también podría asignarla una vez antes de que se ejecute el bucle. Dependiendo de cuán complejo sea el lado derecho de la tarea, esto podría volverse bastante costoso e incluso podría dominar el tiempo de ejecución del ciclo. Si escribe un bucle que usa el mismo valor calculado en todas las iteraciones, definitivamente debe calcularlo por encima del bucle; eso es más importante que minimizar su alcance.

Para aclarar: siempre y cuando compute()siempre devuelva el mismo valor, este

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

es más inteligente que esto:

while (something) {
    int value = compute();
    doSomething(value);
}
Kilian Foth
fuente
2
¿Cómo definirías una variable en el ciclo y la asignarías antes del ciclo?
Hombre enmascarado
66
@ MaskedMan, creo que estás malentendido. Lo que Kilian quiso decir es que si tiene una variable a la que se le asigna el mismo valor durante cada iteración de un ciclo, por ejemplo, se establece la misma variable de fecha 1/1/1900, la variable debe declararse y el valor debe asignarse antes del ciclo.
ps2goat
2
No creo que haya habido un compilador escrito en los últimos veinte años (fuera de un curso de compilación de pregrado) que no se dé cuenta de que está asignando el mismo valor en cada iteración y sacaría esa asignación del ciclo.
TMN
14
@tmn: nunca dejes que un compilador haga lo que puedes hacer trivialmente con mayor claridad de código.
Robert Harvey
10
@ TMN, no necesariamente. Esa optimización solo es posible si el compilador puede demostrar que el cálculo está libre de efectos secundarios.
Paul Draper
16

Los tipos complejos tienen constructores y destructores no triviales.

Esos serán llamados al comienzo y al final del cuerpo del bucle (ya que se inicializa y queda fuera de alcance). Si la inicialización es costosa, ya que necesita asignar algo de memoria, entonces debe evitarse.

Sin embargo, para los tipos triviales no hay problema. La asignación y la desasignación en sí mismas solo suman y restan un valor del puntero de la pila. (que se optimizará)

monstruo de trinquete
fuente
gracias, exactamente la respuesta que estaba buscando!
gebbissimo
6

Bueno, su consejo es un poco demasiado simple (eso es un eufemismo).
Seguirlo va desde una buena idea sobre a quién le importa y una mala idea hasta lo imposible .

  1. Debe seguirlo siempre que reutilizarlo sea más barato que destruir lo viejo y crear uno nuevo.

    #include <iostream>
    #include <string>
    
    int main() {
        std::string s; // Don't needlessly free the buffer
        while ((std::cin >> s))
            std::cout << s;
    }
  2. Debes evitarlo como una cuestión de estilo cuando no importa para el rendimiento.

    #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. Usted realmente debe rechazar cuando se selecciona con peor rendimiento o la semántica equivocadas.

    #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. No puede seguirlo cuando el tipo utilizado no permite ni el intercambio, ni la asignación de movimiento ni la asignación de copia.

    #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;
        }
    }
Deduplicador
fuente
2
Dependiendo de su definición de "en un bucle", 1 puede cambiarse for (std::string s; std::cin >> s;) ...y aún estar "afuera"
Caleth