Creo que mi problema se describe mejor en código:¿El orden de inicialización global de C++ ignora las dependencias?
#include <stdio.h>
struct Foo;
extern Foo globalFoo;
struct Foo {
Foo() {
printf("Foo::Foo()\n");
}
void add() {
printf("Foo::add()\n");
}
static int addToGlobal() {
printf("Foo::addToGlobal() START\n");
globalFoo.add();
printf("Foo::addToGlobal() END\n");
return 0;
}
};
Foo globalFoo;
int dummy = Foo::addToGlobal();
int main() {
printf("main()\n");
return 0;
}
Las impresiones anteriores (con gcc 4.4.3):
Foo::Foo()
Foo::addToGlobal() START
Foo::add()
Foo::addToGlobal() END
main()
Esto es lo que espero, y parece lógico.
Sin embargo, cuando intercambiar las siguientes líneas:
Foo globalFoo;
int dummy = Foo::addToGlobal();
en esto:
int dummy = Foo::addToGlobal();
Foo globalFoo;
emite el programa siguiente:
Foo::addToGlobal() START
Foo::add()
Foo::addToGlobal() END
Foo::Foo()
main()
Parece métodos de instancia de Foo
están siendo llamados usando una instancia que aún no ha sido construido! Algo tan simple como mover la declaración de una variable en el ámbito global está afectando el comportamiento del programa, y eso me lleva a pensar (1) que el orden de inicialización de los globales no está definido y (2) el orden de inicialización de los globales ignora todas las dependencias. ¿Es esto correcto? ¿Es posible asegurarse de que se llama al constructor de Foo
antes de inicializar dummy
?
El problema que estoy tratando de resolver es llenar un depósito de elementos (una instancia estática de Foo
) estáticamente. En mi intento actual, estoy usando una macro que (entre otras cosas) crea una variable global (en un espacio de nombres anónimo para evitar el conflicto de nombres) cuya inicialización desencadena la inicialización estática. Tal vez estoy abordando mi problema desde el ángulo equivocado? ¿Hay una mejor alternativa (s)? Gracias.
Encontré esta solución después de publicar mi pregunta. Lo intenté, y parece funcionar. Sin embargo, puede haber un problema: ¿habrá múltiples instancias debido a 'static' dentro de' singleton'? Es decir, ¿podría 'Foo :: singleton()' devolver cosas diferentes si se declara y define en un archivo de cabecera y se incluye en varias unidades de traducción? – strager
Otro posible problema con este patrón es que AFAIK no es seguro para acceder a Singleton al mismo tiempo. – FuleSnabel
@strager: cuando la variable local se declara 'static ', habrá una sola instancia de la misma, incluso si la función está en línea (es decir, compilada por separado en diferentes unidades de traducción), el enlazador debe asegurarse de que solo una definición única de la variable existe –