2011-12-08 9 views
16

Ejemplo:C++ inicialización estática vs __ __attribute ((constructor))

struct Foo { Foo() { printf("foo\n"); } }; 
static Foo foo; 

__attribute__((constructor)) static void _bar() { printf("bar\n"); } 

Es determinista wether foo o bar se imprime primero?

(espero y esperaría que los constructores de objetos estáticos siempre se ejecutan primero, pero no está seguro y GCC doc sobre el atributo constructor no dice nada al respecto.)

+0

¿Dónde se usa ese tipo de características de compilación? – AlexTheo

+0

@AlexTheo: Eso es bastante común. Ver p. . Usualmente lo usas cada vez que quieres inicializar algo. – Albert

+0

En realidad, prefiero algo así como static const bool _isInitialized y haciendo una función de inicialización privada con la que inicializo mi objeto como const bool MyClass :: _ isInitialized = initFunction(); Pero estos son solo para objetos que me gusta inicializar antes que nada. De lo contrario, el constructor debería hacer un trabajo. – AlexTheo

Respuesta

13

foo se imprimirán en primer lugar, como el los objetos se inicializan en el orden de sus declaraciones. Correr y ver:

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

El doc dice,

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

Puede proporcionar una prioridad entera opcional para controlar el orden en que se ejecutan las funciones de constructor y 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 vale para los destructores. Por lo tanto, si tiene un constructor que asigna un recurso y un destructor que desasigna el mismo recurso, ambas funciones suelen tener la misma prioridad. Las prioridades para las funciones constructor y destructor son las mismas que las especificadas para los objetos C++ de ámbito de nombre de espacio (ver Atributos C++).

creo que el texto en negrita indica, los objetos se inicializan en el orden de sus declaraciones, como he dicho antes, que está prácticamente confirmado por online demo también.

supongo que también le gustaría leer esto:

Si desea controlar/alterar el orden de inicialización, puede utilizar init_priority atributo, proporcionando prioridad. Tomado de the page:

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

Aquí, B se inicializa antes A.

+0

Hm, ¿se han eliminado todos los comentarios? Cómo es eso posible. Entonces, aquí está mi comentario de nuevo: Lo más interesante para mí fue esta información junto con el último enlace, esp. esto: * En el Estándar C++, se garantiza que los objetos definidos en el ámbito del espacio de nombres se inicialicen en un orden estrictamente de acuerdo con sus definiciones en una unidad de traducción dada. * – Albert

+0

En realidad, acabo de probarlo en otro ejemplo, y no lo hace parece ser el caso allí. – Albert

+0

@Albert: Publique el código. El código real, sin cambiarlo un poco. También publique la salida que obtiene. – Nawaz

1

Parece no determinista. También tuve foo\nbar\n como la salida del ejemplo en mi pregunta cuando se compiló con GCC. Sin embargo, cuando se compila con LLVM/Clang, obtengo bar\nfoo\n.

Pero, como no estoy seguro de si esto podría ser un error en Clang, llené un informe de error here. Editar: Recibí 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 el que debería ser realmente es determinista aquí, sin embargo, no se puede depender de él ya que hay al menos un compilador principal (Clang) que lo hace incorrecto (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. P.ej. here es un ejemplo que genera un generador aleatorio que falla con Clang.

+0

Eliminar esta publicación. Y edite su pregunta, y publíquela aquí. Una respuesta debería ser una respuesta, no una pregunta. – Nawaz

+1

@Nawaz: ¿Qué quieres decir? ¿Por qué? Esta es una respuesta, mi pregunta es una pregunta. Si no está claro para usted cómo responde esta respuesta, es la pregunta real: básicamente dice que es indeterminista. – Albert

+0

De acuerdo. ¿Cómo se puede decir que no es determinista, y cómo se puede decir esto: "* Entonces, parece que el constructor de rnd se ejecuta después de _rand_engine__init *". Publica una explicación también! – Nawaz

Cuestiones relacionadas