c++ gcc static-initialization

C++ inicialización estática vs__attribute__((constructor))



gcc static-initialization (2)

Parece no determinista. También tuve foo/nbar/n como resultado del ejemplo en mi pregunta cuando se compila con GCC. Sin embargo, cuando se compila con LLVM / Clang, me sale la bar/nfoo/n .

Pero, como no estoy seguro de si esto podría ser un error en Clang, completé un informe de error here . Edit: obtuve una respuesta allí y parece ser realmente un error en Clang que aún no está solucionado. No estoy seguro de qué concluir de eso. El comportamiento esperado y que debería ser realmente es determinista aquí, sin embargo, no puede depender de él ya que hay al menos un compilador principal (Clang) que lo hace mal (o diferente a GCC, si tomamos eso como la especificación para __attribute__((constructor)) ).

Tenga en cuenta que esto puede ser realmente relevante e importante en el código del mundo real. Por ejemplo, here hay un ejemplo que siembra un generador aleatorio que falla con Clang.

Ejemplo:

struct Foo { Foo() { printf("foo/n"); } }; static Foo foo; __attribute__((constructor)) static void _bar() { printf("bar/n"); }

¿Es determinista si foo o bar se imprime primero?

(Espero y espero que los constructores de objetos estáticos siempre se ejecuten primero, pero no estoy seguro, y los documentos de GCC sobre el atributo del constructor no dicen nada al respecto).


Primero se imprimirá foo , ya que los objetos se inicializan en el orden de sus declaraciones. Corre y ve:

Por cierto, __attribute__((constructor)) no es Standard C ++. Es la extensión de GCC. Entonces, el comportamiento de su programa depende de cómo GCC lo haya definido. En resumen, está definido por la implementación, de acuerdo con esto, foo se imprime primero.

El doc dice:

El atributo constructor hace que la función se llame automáticamente antes de que la ejecución ingrese main (). De manera similar, el atributo destructor hace que la función se llame automáticamente después de que se haya completado main () o se haya llamado a exit (). Las funciones con estos atributos son útiles para inicializar los datos que se utilizarán implícitamente durante la ejecución del programa.

Puede proporcionar una prioridad de entero opcional para controlar el orden en que se ejecutan las funciones del constructor y del destructor. Un constructor con un número de prioridad más pequeño se ejecuta antes que un constructor con un número de prioridad más grande; La relación opuesta es válida para los destructores. Por lo tanto, si tiene un constructor que asigna un recurso y un destructor que desasigna el mismo recurso, ambas funciones generalmente tienen la misma prioridad. Las prioridades para las funciones de constructor y destructor son las mismas que las especificadas para los objetos C ++ de ámbito de espacio de nombres (ver Atributos de C ++).

Creo que el texto en negrita implica que los objetos se inicializan en el orden de sus declaraciones, como dije antes, lo cual está bastante confirmado por la demostración en línea también.

Supongo que también te gustaría leer esto:

Si desea controlar / alterar el orden de inicialización, puede usar el atributo init_priority , dando prioridad . Tomado de la página :

Some_Class A __attribute__ ((init_priority (2000))); Some_Class B __attribute__ ((init_priority (543)));

Aquí, B se inicializa antes de A