2012-02-01 18 views
5

Estoy compilando una biblioteca compartida con dos unidades de compilación: globals.cpp y stuff.cpp. El archivo globals.cpp inicializa un puñado de variables externas que se usan en stuff.cpp. El problema que estoy experimentando es que el código en stuff.cpp se está ejecutando antes de que el código en globals.cpp haya tenido la oportunidad de asignar un valor a las variables externas. Por ejemplo, veo que se utilizan varios valores de 0. Este problema depende de en qué plataforma compile/ejecute el código, algo de trabajo y otros no.¿Por qué aún no se ha inicializado mi variable externa?

¿Cómo se soluciona esto? ¿Puedo forzar globals.cpp a ejecutar primero?

+3

Usted está experimentando el [fiasco de la orden de inicialización estática] [1]. [1]: http://stackoverflow.com/questions/3035422/static-initialization-order-fiasco – kfmfe04

+0

Gracias, eso al menos aclara el problema. – sholsapp

Respuesta

6

Puede no (de una manera consistente)

Pero se puede trabajar alrededor de ella.

Global.cpp

// If you have a global variable that has to be initial by a constructor 
MyObj globalX; 

// Instead do this 

MyObj& globalX() { static MyObj x; return x;} 

Usted todavía tiene una variable global. Pero al ponerlo en una función, sabemos cuándo se está utilizando. Al usar un miembro estático de la función, se inicializa la primera vez que se llama a la función, pero no después de eso. Por lo tanto, usted sabe que se construirá correctamente antes del primer uso.

+0

Esto resolvió el problema. – sholsapp

2
+0

Como es habitual, las preguntas frecuentes dan un mal consejo. El uso de punteros significa que los objetos no se destruyen consistentemente y el siguiente punto sobre los problemas con el orden de destrucción es simplemente incorrecto: http: // stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems # 335746 –

+0

@LokiAstari: Interesante. ¿Está completamente equivocado? La FAQ menciona "Si los constructores de a, byc usan ans, normalmente debería estar bien, ya que el sistema de tiempo de ejecución, durante la desinicialización estática, destruirá después de que el último de esos tres objetos sea destruido", aunque estoy de acuerdo en que no debería ser tan desdeñoso. – jamesdlin

+0

Él descarta fugas como un problema porque la memoria está limpia por el sistema operativo. Esto es simplemente ** descuidado y MALO **. Cualquier cosa con un constructor/destructor no es realmente la memoria; se trata de los recursos que tienen estos objetos y su limpieza. Puede haber algo en estos objetos y cuando modificas un objeto, verificas todos los lugares en los que "fuga intencionalmente" para asegurarte de que la filtración no está afectando la corrección de tus códigos (supongo que ni siquiera puedes encontrar estos lugares). Entonces, la única vez que su comentario es relevante es para cosas sin constructor/destructor. –

0

Asumo que está viendo este behavious porque están haciendo en línea inicialización de variables globales sin una llamada de función explícita. p.ej. globals.cpp:

// top of source file 

#include "myincludes.h" 

CSomeClass someObject(432); 
int global_x = 42; 
int global_y = InitY(); 

El orden constructor y el destructor de objetos globales y orden global inicialización de variables es en su mayoría no determinista. (Conjeturo, sin consultar las páginas de referencia estándar, que las variables en un archivo fuente se inicialicen desde la declaración superior a la inferior, pero el orden de "qué archivo fuente es primero" no está definido.)

La mejor solución es no tener ningún objeto global (donde el constructor se ejecuta antes de cualquier función en la biblioteca) o tener una dependencia en el orden de inicialización de la variable global.

Es mejor tener una función que inicialice explícitamente su biblioteca. Tal vez requiera que la aplicación llame a esta función una al inicio o las funciones exportadas de su biblioteca la llamen después de detectar que la inicialización no se ha producido. Inicializa tus globales entonces.

En mi equipo, el código que se ejecuta antes de "principal" (o "DllMain") está estrictamente prohibido. En otras palabras, no hay objetos globales. No hay funciones para iniciar globals.

Cuestiones relacionadas