2011-04-06 12 views
40

Me di cuenta de que si inicializa una variable estática en C++ en el código, la inicialización solo se ejecuta la primera vez que ejecuta la función.¿Qué hace que una variable estática se inicialice solo una vez?

Eso es genial, pero ¿cómo se implementa eso? ¿Se traduce a algún tipo de declaración retorcida? (Si se le da un valor, entonces ..)

void go(int x) 
{ 
    static int j = x ; 
    cout << ++j << endl ; // see 6, 7, 8 
} 

int main() 
{ 
    go(5) ; 
    go(5) ; 
    go(5) ; 
} 
+6

¿Cómo se implementa _por qué compilador_? –

Respuesta

48

Sí, se traduce normalmente en una declaración implícita if con una bandera booleana interna. Así, en la realización más básica de su declaración que habitualmente se traduce en algo así como

void go(int x) { 
    static int j; 
    static bool j_initialized; 

    if (!j_initialized) { 
    j = x; 
    j_initialized = true; 
    } 

    ... 
} 

Además de eso, si su objeto estático tiene un destructor no trivial, el lenguaje tiene que obedecer a otra regla: este tipo de objetos estáticos tienen que ser destruido en el orden inverso de su construcción. Como la orden de construcción solo se conoce en tiempo de ejecución, la orden de destrucción también se define en el tiempo de ejecución. Entonces, cada vez que construyes un objeto estático local con un destructor no trivial, el programa tiene que registrarlo en algún tipo de contenedor lineal, que luego usará para destruir estos objetos en el orden correcto.

No hace falta decir que los detalles reales dependen de la implementación.


Vale la pena añadir que cuando se trata de objetos estáticos de tipos "primitivos" (como int en su ejemplo) inicializados con constantes de tiempo de compilación, el compilador es libre para inicializar ese objeto en el arranque. Nunca notarás la diferencia. Sin embargo, si se toma un ejemplo más complicado con un objeto "no primitivos"

void go(int x) { 
    static std::string s = "Hello World!"; 
    ... 

entonces el enfoque anterior con if es lo que debe esperar encontrar en el código generado, incluso cuando el objeto se inicializa con una compilación -tiempo constante.

En su caso, el inicializador no se conoce en tiempo de compilación, lo que significa que el compilador tiene que retrasar la inicialización y usar ese implícito if.

+2

Pensé que las estáticas eran realmente globales, por lo que se comparten entre hilos ... Y al ser globales, se inicializan solo una vez ... – dicroce

+3

@dicroce, las variables estáticas dentro de las funciones son diferentes de las globales reales: se inicializan perezosamente, en la primera llamada de la función adjunta. Por lo tanto, necesita alguna forma de control dentro de la función. –

+1

@dicroce: las estadísticas locales se inicializan * como máximo * una vez. Pero no se sabe de antemano * cuando * se inicializarán. Y es posible que no se inicialicen en absoluto (si el control nunca se ejecuta sobre la declaración). – AnT

2

Si bien es "una especie de trenzado si", el giro puede ser más de lo que imaginaba ...

comentario de ZoogieZork sobre la respuesta de AndreyT toca un aspecto importante: la inicialización de variables locales estáticas - en algunos compiladores incluyendo GCC - es por defecto hilo seguro (una opción de línea de comandos del compilador puede deshabilitarlo). En consecuencia, está utilizando algún mecanismo de sincronización entre subprocesos (una operación mutex o atómica de algún tipo) que puede ser relativamente lento. Si no se siente cómodo (en cuanto al rendimiento) con el uso explícito de dicha operación en su función, debe considerar si existe una alternativa de menor impacto a la inicialización diferida de la variable (es decir, construirla explícitamente de una manera segura para usted mismo en algún lugar solo una vez).Sin embargo, son muy pocas las funciones tan sensibles al rendimiento que esto importa: no permitas que arruinen tu día o que el código sea más complicado, a menos que tus programas se vuelvan demasiado lentos y tu perfil toque esa área.

+0

'en algunos compiladores' es incorrecto: es ** obligatorio ** que la inicialización estática sea segura para subprocesos. ver: http://stackoverflow.com/q/8102125/2757035 –

+1

@underscore_d: esta respuesta fue escrita para C++ 03, si quieres decir que las cosas cambiaron a partir de C++ 11 noquearte ... –

1

Se inicializan solo una vez porque eso es lo que exige el estándar C++. Cómo esto sucede depende completamente de los vendedores del compilador. En mi experiencia, el compilador genera y usa un marcador oculto local.

Cuestiones relacionadas