Pregunta

Estoy trabajando en algo de código C ++ y me he topado con una pregunta que me ha sido molestando por un tiempo ... Suponiendo que estoy compilar con GCC en un host Linux para un objetivo ELF, donde son estáticos mundial constructores y destructores llamada?

He oído que hay una función en _init crtbegin.o, y una función en _fini crtend.o. Son estos llamados por crt0.o? ¿O es que el enlazador dinámico realidad detectar su presencia en el binario cargado y los llaman? Si es así, cuando es lo que realmente les llaman?

Estoy principalmente interesado en saber así que puedo entender lo que está sucediendo detrás de las escenas que se ha cargado el código, ejecutado, y luego descargadas en tiempo de ejecución.

Gracias de antemano!

Actualización: básicamente estoy tratando de averiguar el tiempo general en la cual se llaman los constructores. No quiero hacer suposiciones en mi código en base a esta información, es más o menos para tener una mejor comprensión de lo que está sucediendo en los niveles más bajos cuando mi programa carga. Entiendo que esto es bastante específico del SO, pero he tratado de reducirlo un poco en esta cuestión.

¿Fue útil?

Solución

Cuando se habla de objetos estáticos no locales que no hay muchas garantías. Como ya saben (y también se han mencionado aquí), no debe escribir código que depende de eso. El orden de inicialización estática fiasco ...

Los objetos estáticos pasa a través de una inicialización de dos fases: inicialización estática y la inicialización dinámica. El primero ocurre primero y realiza la inicialización de cero o inicialización por las expresiones constantes. Este último sucede después de todo inicialización estática se realiza. Esto es cuando son llamados constructores, por ejemplo.

En general, esta inicialización sucede en algún momento antes de main (). Sin embargo, a diferencia de lo que muchos piensan incluso que no está garantizado por la norma C ++. Lo que está garantizado, de hecho, es que la inicialización se realiza antes de que el uso de cualquier función u objeto definido en la misma unidad de traducción como el objeto que se está inicializado. Tenga en cuenta que esto no es específica del sistema operativo. Esto es reglas C ++. He aquí una cita de la norma:

Es definido por la implementación si o no la inicialización dinámica (8.5, 9.4, 12.1, 12.6.1) de un objeto de ámbito de espacio de nombres se hace antes de la primera declaración del principal. Si la inicialización se difiere hasta cierto punto en el tiempo después de la primera declaración del principal, deberá producirse antes del primer uso de cualquier función o un objeto definido en la misma unidad de traducción como el objeto a ser inicializado

Otros consejos

Esto no es específica del sistema operativo, más bien su compilador específico.

Usted ha dado la respuesta, la inicialización se realiza en __init.

Para la segunda parte, en gcc que se puede garantizar el orden de inicialización con un ____attribute____((init_priority(PRIORITY))) unido a una definición de variable, donde PRIORITY es un valor relativo, con los números más bajos inicializa por primera vez.

Esto depende pesado en el compilador y el tiempo de ejecución. No es una buena idea hacer ninguna suposición sobre el tiempo de objetos globales se construyen.

Esto es especialmente un problema si usted tiene un objeto estático que depende de ser otra ya construida.

Esto se llama " orden de inicialización estática fiasco ". Incluso si eso no es el caso en su código, los artículos FAQ C ++ Lite en ese tema son vale la pena leer.

Los beneficiarios que tienen:

  • Todos los objetos que no son locales estáticos en el espacio de nombres global se construyen antes de main ()
  • Todos los objetos que no son locales estáticos en otro espacio de nombres se construyen antes de cualquiera de las funciones / métodos se utilizan en ese espacio de nombres (lo tanto permitiendo que el compilador potencialmente perezoso a evaluar [pero no cuentan con este comportamiento]).
  • Todos los objetos que no son locales estáticas en una unidad de traducción se construyen en el orden de declaración.
  • Nada se define por el orden entre las unidades de traducción.
  • Todos los objetos no estáticos locales son destruidos en el orden inverso de la creación. (Esto incluye las variables de la función estática (que se crean con pereza en el primer uso).

Si usted tiene globales que tienen dependencias entre sí tiene dos opciones:

  • Póngalos en la misma unidad de traducción.
  • transformarlos en variables de la función estáticas recuperados y construidos en el primer uso.

Ejemplo 1: constructor de Global A utiliza log Global

class AType
{    AType()  { log.report("A Constructed");}};

LogType    log;
AType      A;

// Or 
Class AType() 
{    AType()  { getLog().report("A Constructed");}};
LogType& getLog()
{
    static LogType  log;
    return log;
}
// Define A anywhere;

destructor del Ejemplo Global B utiliza de registro Global

Aquí hay que concesionario que el registro de objeto no se destruye antes de que el objeto B. Esto significa que registro debe estar totalmente construido antes de que B (como entonces se aplicará el orden inverso de la regla de destrucción). De nuevo las mismas técnicas se pueden utilizar. O bien ponerlos en la misma unidad de traducción o utilizar una función para obtener registro.

class BType
{    ~BType()  { log.report("B Destroyed");}};

LogType    log;
BType      B;   // B constructed after log (so B will be destroyed first)

// Or 
Class BType() 
{    BType()    { getLog();}
     /*
      * If log is used in the destructor then it must not be destroyed before B
      * This means it must be constructed before B 
      * (reverse order destruction guarantees that it will then be destroyed after B)
      *
      * To achieve this just call the getLog() function in the constructor.
      * This means that 'log' will be fully constructed before this object.
      * This means it will be destroyed after and thus safe to use in the destructor.
      */
    ~BType()    { getLog().report("B Destroyed");}
};
LogType& getLog()
{
    static LogType  log;
    return log;
}
// Define B anywhere;

Según el estándar de la C ++ se les llama antes de utilizar cualquier función o objeto de su unidad de traducción. Tenga en cuenta que para los objetos en el espacio de nombres global que ello significaría que se inicializan antes main() se llama. (Ver de ltcmelo respuestas de Martin como mote detalles y una discusión sobre esto.)

scroll top