miembros estaticos estaticas c++ c++11

estaticas - miembros estaticos c++



Está garantizado que el objeto estático se inicializa (3)

Estoy tratando de aprender sobre la inicialización de objetos estáticos. La inicialización estática parece bastante directa, suponiendo que comprende expresiones constantes y constexpr . La inicialización dinámica parece un poco más complicada.

[basic.start.init] / 4

Se define en la implementación si la inicialización dinámica de una variable no local con duración de almacenamiento estática se realiza antes de la primera declaración de main. Si la inicialización se difiere en algún punto en el tiempo después de la primera declaración de main, debe ocurrir antes del primer odr-uso (3.2) de cualquier función o variable definida en la misma unidad de traducción que la variable a ser inicializada.

nota 34

Una variable no local con una duración de almacenamiento estática que tiene inicialización con efectos laterales debe inicializarse incluso si no se utiliza (3.2, 3.7.1).

[basic.start.init] / 5

Se define en la implementación si la inicialización dinámica de una variable no local con duración estática o de almacenamiento de subprocesos se realiza antes de la primera declaración de la función inicial del subproceso. Si la inicialización se difiere en algún punto en el tiempo después de la primera declaración de la función inicial del hilo, debe ocurrir antes del primer uso odr (3.2) de cualquier variable con duración de almacenamiento de hilo definida en la misma unidad de traducción que la variable ser inicializado

Supongo que "la función inicial del hilo" se refiere a main, y no solo a los hilos iniciados con std :: thread.

h1.h

#ifndef H1_H_ #define H1_H_ extern int count; #endif

tu1.cpp

#include "h1.h" struct S { S() { ++count; } }; S s;

tu2.cpp

#include "h1.h" int main(int argc, char *argv[]) { return count; }

tu3.cpp

#include "h1.h" int count;

Por lo tanto, si un compilador difiere la inicialización dinámica, parece que la nota al pie 34 indica que s debe inicializarse en algún punto. Como no hay otras variables con inicialización dinámica en la unidad de traducción, no hay otra variable que usar odr para forzar la inicialización de las variables en tu1. ¿En qué punto se garantiza que se haya inicializado?

¿Está garantizado que main devolverá 1? Además, ¿hay alguna forma de cambiar este programa para que ya no se garantice que devuelva 1? Alternativamente, si no está garantizado, ¿hay alguna forma de cambiar este programa para que esté garantizado?

Rompí el código para que la definición de s esté en una unidad de traducción diferente de la main . Esto evita la pregunta de si main es odr usado. Dado que s es el único objeto en la unidad de traducción, ¿se garantiza que el main devolverá 1?


"el primer uso de odr de cualquier función o variable definida en la misma unidad de traducción que la variable a inicializar" incluye la variable que se va a inicializar.


Creo que toda esta redacción está ahí para describir lo que sucederá en las bibliotecas cargadas dinámicamente, pero sin nombrarlas explícitamente.

Para resumir cómo lo interpreto: una variable no local con duración de almacenamiento estático e inicialización dinámica:

  1. inicializarse antes del primer uso odr de cualquier cosa en su unidad de traducción;
  2. posiblemente, antes de iniciar main , pero posiblemente después de esto.

Interpreto la nota al pie 34 como (pero recuerde que las notas a pie de página no son normativas):

Cuando se usa cualquier cosa en una TU, se deben inicializar todas las variables no locales con duración de almacenamiento estático con inicialización con efectos laterales, incluso las variables que no se utilizan.

Entonces, si hay una TU donde no se usa nada, entonces sus inicializaciones dinámicas pueden no suceder.

Ejemplo

h1.h

extern int count; struct S { S(); };

h1.cpp

#include "h1.h" int count; S::S() { ++count; }

h2.cpp

#include "h1.h" S s;

main.cpp

#include "h1.h" #include <stdio.h> int main() { printf("%d/n", count); }

Esto podría imprimir 0 o 1: dado que cualquier cosa en TU h2 nunca se utiliza, no se especifica cuando la inicialización de código de s se realizará, si s que se hace.

Naturalmente, los compiladores sanos inicializarán s antes que main, por lo que seguramente imprimirá 1 :

$ g++ main.cpp h2.cpp h1.cpp -o test1 $ ./test1 1

Ahora, imagina que h2.cpp está en una biblioteca compartida:

$ g++ -shared -fPIC h2.cpp -o h2.so

Y el archivo principal ahora es:

main2.cpp

#include "h1.h" #include <dlfcn.h> #include <stdio.h> int main() { printf("%d/n", count); dlopen("./h2.so", RTLD_NOW); printf("%d/n", count); return 0; }

Compilar y ejecutar:

$ g++ -shared -fPIC h2.cpp -o h2.so $ g++ -rdynamic main.cpp h1.cpp -ldl -o test2 $ ./test2 0 1

¿Ver? ¡La inicialización de s se ha retrasado! Lo bueno es que es imposible hacer referencia a cualquier cosa en la biblioteca cargada dinámicamente sin antes cargarlo, y al cargarlo se activará la inicialización dinámica. Entonces todo está bien.

Si cree que usar dlopen es una trampa, recuerde que hay compiladores que admiten cargar bibliotecas compartidas (por ejemplo, VC ++), donde la compilación solo genera la llamada del sistema para cargar la biblioteca la primera vez que se necesita.


Sin buscar las páginas correctas en la definición, puedo decir que su programa está garantizado para regresar 1. Cada inicialización estática o global se realiza antes del primer comando en la principal. Las variables globales se inicializan primero y luego se ejecutan los constructores de los objetos globales. Estática dentro de un ámbito de función / método inicializada antes del primer uso. Pero hay una trampa:

int count; struct A { A() { count=5; } }; struct B { B() { count=count*2; } }; A a; B b; void main(void) { return count; }

Como se menciona en un comentario de Ben Voigt, el resultado se define si ambas instancias se crean en la misma unidad de traducción. Entonces en mi ejemplo, el resultado es 10. Si las instancias se crean en diferentes archivos (y se compilan por separado a diferentes archivos .obj), el resultado no está definido.