¿Hay alguna sobrecarga para declarar una variable dentro de un bucle? (C++) [duplicado]


Esta pregunta ya tiene una respuesta aquí:

Me pregunto si habría alguna pérdida de velocidad o eficiencia si hicieras algo como esto:

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

Que declara int var cien veces. Me parece que lo habría, pero no estoy seguro. sería sea más práctico / más rápido para hacer esto en su lugar:

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

¿O son los mismos, rápidos y eficientes?

Author: laalto, 2009-06-11

13 answers

El espacio de pila para las variables locales generalmente se asigna en el ámbito de la función. Así que no hay ajuste de puntero de pila ocurre dentro del bucle, sólo asignando 4 a var. Por lo tanto, estos dos fragmentos tienen la misma sobrecarga.

 186
Author: laalto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 19:03:52

Para tipos primitivos y tipos POD, no hace ninguna diferencia. El compilador asignará el espacio de pila para la variable al principio de la función y desasignar cuando se devuelve la función en ambos casos.

Para los tipos de clase no POD que tienen constructores no triviales, hará una diferencia -- en ese caso, poner la variable fuera del bucle solo llamará al constructor y destructor una vez y al operador de asignación cada iteración, mientras que ponerlo dentro de la loop llamará al constructor y destructor para cada iteración del bucle. Dependiendo de lo que hagan el constructor, destructor y operador de asignación de la clase, esto puede o no ser deseable.

 96
Author: Adam Rosenfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 20:23:39

Ambos son los mismos, y así es como puedes averiguarlo, mirando lo que hace el compilador (incluso sin optimización establecida en alto):

Mira lo que el compilador (gcc 4.0) hace a tus ejemplos simples:

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

De estos, se pueden ver dos cosas: en primer lugar, el código es el mismo en ambos.

En segundo lugar, se asigna el almacenamiento para var fuera del bucle:

         subl    $24, %esp

Y finalmente lo único en el bucle es la verificación de asignación y condición:

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

Que es lo más eficiente que puede ser sin eliminar el bucle por completo.

 66
Author: Alex Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 19:55:47

En estos días es mejor declararlo dentro del bucle a menos que sea una constante, ya que el compilador podrá optimizar mejor el código (reduciendo el alcance de la variable).

EDITAR: Esta respuesta está casi obsoleta ahora. Con el auge de los compiladores postclásicos, los casos en los que el compilador no puede averiguarlo se están volviendo raros. Todavía puedo construirlos pero la mayoría de la gente clasificaría la construcción como código malo.

 12
Author: Joshua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-22 16:24:27

La mayoría de los compiladores modernos optimizarán esto para usted. Dicho esto, usaría su primer ejemplo, ya que lo encuentro más legible.

 10
Author: Andrew Hare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-07 05:09:06

Para un tipo incorporado probablemente no habrá diferencia entre los 2 estilos (probablemente hasta el código generado).

Sin embargo, si la variable es una clase con un constructor/destructor no trivial bien podría haber una diferencia importante en el costo de tiempo de ejecución. Yo generalmente alcance la variable dentro del bucle (para mantener el ámbito tan pequeño como sea posible), pero si eso resulta tener un impacto perf Yo buscaría mover la variable de clase fuera del ámbito del bucle. Sin embargo, haciendo eso necesita algún análisis adicional ya que la semántica de la ruta de la oda puede cambiar, por lo que esto solo se puede hacer si la semática lo permite.

Una clase RAII podría necesitar este comportamiento. Por ejemplo, es posible que deba crearse y destruirse una clase que administre la duración del acceso a los archivos en cada iteración de bucle para administrar el acceso a los archivos correctamente.

Supongamos que tiene una clase LockMgr que adquiere una sección crítica cuando se construye y la libera cuando se destruye:

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

Es bastante diferente de:

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

    // do stuff...

}
 8
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-12 00:41:58

Ambos bucles tienen la misma eficiencia. Ambos tomarán una cantidad infinita de tiempo:) Puede ser una buena idea incrementar i dentro de los bucles.

 6
Author: Larry Watanabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 20:27:15

Una vez realicé algunas pruebas de rendimiento, y para mi sorpresa, ¡descubrí que el caso 1 era en realidad más rápido! Supongo que esto puede ser porque declarar la variable dentro del bucle reduce su alcance, por lo que se libera antes. Sin embargo, eso fue hace mucho tiempo, en un compilador muy antiguo. Estoy seguro de que los compiladores modernos hacen un mejor trabajo optimizando las diferencias, pero aún así no hace daño mantener su alcance variable lo más corto posible.

 2
Author: user3864776,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-27 14:13:10
#include <stdio.h>
int main()
{
    for(int i = 0; i < 10; i++)
    {
        int test;
        if(i == 0)
            test = 100;
        printf("%d\n", test);
    }
}

El código anterior siempre imprime 100 10 veces lo que significa que la variable local dentro del bucle solo se asigna una vez por cada llamada a la función.

 1
Author: Byeonggon Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-13 14:57:06

La única manera de estar seguro es cronometrarlos. Pero la diferencia, si hay una, será microscópica, por lo que necesitará un poderoso bucle de tiempo grande.

Más concretamente, el primero es mejor estilo porque inicializa la variable var, mientras que el otro la deja sin inicializar. Esto y la directriz de que se deben definir variables lo más cerca posible de su punto de uso, significa que normalmente se debe preferir la primera forma.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 19:15:31

Con solo dos variables, el compilador probablemente asignará un registro para ambas. Estos registros están allí de todos modos, así que esto no toma tiempo. Hay 2 register write y una instrucción register read en cualquier caso.

 -1
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-12 15:20:57

Creo que a la mayoría de las respuestas les falta un punto importante a considerar que es: "Está claro" y obviamente por toda la discusión el hecho es; no, no lo es. Sugeriría que en la mayoría de los códigos de bucle la eficiencia es prácticamente un problema (a menos que calcules para un módulo de aterrizaje mars), así que realmente la única pregunta es qué se ve más sensible y legible y mantenible - en este caso, recomendaría declarar la variable por adelantado y fuera del bucle - esto simplemente lo hace más claro. Entonces la gente como tú y yo ni siquiera se molestaría en perder el tiempo comprobando en línea para ver si es válido o no.

 -2
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-05 05:20:55

Eso no es cierto hay gastos generales sin embargo su negligencia puede gastos generales.

Aunque probablemente terminarán en el mismo lugar de la pila, todavía lo asigna. Asignará la ubicación de la memoria en la pila para esa int y luego la liberará al final de }. No en el sentido libre del montón en sentido se moverá sp (puntero de pila) por 1. Y en su caso, considerando que solo tiene una variable local, simplemente igualará fp (puntero de marco) y sp

La respuesta corta sería: NO IMPORTA DE NINGUNA MANERA FUNCIONA CASI IGUAL.

Pero intenta leer más sobre cómo se organiza la pila. Mi escuela de pregrado tuvo muy buenas conferencias sobre eso. Si quieres leer más consulta aquí http://www.cs.utk.edu / ~plank/plank/classes/cs360/360/notes/Assembler1/lecture.html

 -6
Author: grobartn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-11 19:24:44