2009-10-08 8 views
5

estaba leyendo las Qt convenciones de codificación documentos y me encontré con el siguiente párrafo:C++ estática global sin fines de POD: teoría y práctica

Cualquier cosa que tiene un constructor o necesita para ejecutar código que ser inicializado no se puede utilizar como objeto global en el código de la biblioteca, ya que no está definido cuando ese constructor/código se ejecutará (en el primer uso, en la carga de la biblioteca, antes de main() o en absoluto). Incluso si el tiempo de ejecución del inicializador se define para bibliotecas compartidas, tendrá problemas al mover ese código en un complemento o si la biblioteca está compilada estáticamente.

Sé lo que dice theory, pero no entiendo la parte "nada". A veces utilizo estadísticas estáticas no relacionadas con POD (por ejemplo, QString) y nunca se me ocurrió que podrían no haberse inicializado ... ¿Es esto específico de los objetos compartidos/DLL? ¿Esto sucede solo para compiladores rotos?

¿Qué opinas sobre esta regla?

+0

Su QString puede no inicializarse si no las usa. Pero si los usa, se inicializarán. Incluso si esto es justo antes del uso (es decir, justo antes de que se invoque un método sobre el objeto). –

Respuesta

8

La parte "no, en absoluto" simplemente dice que el estándar C++ no dice nada sobre este problema. No sabe sobre bibliotecas compartidas y, por lo tanto, no dice nada sobre la interacción de ciertas características de C++ con estas.

En la práctica, he visto variables globales estáticas no POD globales utilizadas en Windows, OSX y muchas versiones de Linux y otros Unices, tanto en GUI como en programas de línea de comandos, como complementos y como aplicaciones independientes. Al menos un proyecto (que utilizaba variables globales estáticas no POD) tenía versiones para el conjunto completo de todas las combinaciones de estos. El único problema que he visto es que una versión muy antigua de GCC generó un código que llamaba a los controladores de dichos objetos en las bibliotecas dinámicas cuando el ejecutable se detenía, no cuando la biblioteca estaba descargada. Por supuesto, eso fue fatal (el código de la biblioteca se llamó cuando la biblioteca ya no estaba), pero eso fue hace casi una década.

Pero, por supuesto, esto todavía no garantiza nada.

2

No creo que puedan eliminarse los constructores de objetos estáticos. Probablemente haya una confusión con el hecho de que una biblioteca estática a menudo es simplemente un grupo de objetos que se muestran en el ejecutable si se hace referencia a ellos en. Algunos objetos estáticos están diseñados para que no se mencionen fuera de su objeto contenedor, por lo que el archivo del objeto se coloca en el ejecutable solo si existe otra dependencia en ellos. Este no es el caso en algunos patrones (usando un objeto estático que se registra, por ejemplo).

+0

Creo que está confundiendo "objeto estático" con "biblioteca estática". – sbi

+1

Por "objetos estáticos" quise decir "objetos con duración de almacenamiento estática". Por cierto, he encontrado la referencia que dice que no se pueden eliminar si su inicialización o destructor tiene un efecto secundario: 3.7.1/2. – AProgrammer

+0

Quise decir que las bibliotecas estáticas probablemente no sean un problema aquí. Sus bibliotecas dinámicas son el problema. – sbi

2

Si el objeto estático se define en un objeto que no recibe referencias, el enlazador puede podar el objeto por completo, incluido el código del inicializador estático. Es lo hará regularmente para libs (así es como la libc no se vincula por completo al usar partes de ella bajo gnu, por ejemplo).

Curiosamente, no creo que esto sea específico de las bibliotecas. Probablemente puede suceder para objetos incluso en la construcción principal.

2

No veo ningún problema con tener objetos globales con constructores.

Simplemente no deberían tener ninguna dependencia en otros objetos globales en su constructor (o destructor).

Pero si tienen dependencias, entonces el objeto dependiente debe hacerlo en la misma unidad de compilación o ser evaluado de forma perezosa para que pueda forzarlo a evaluar antes de usarlo.

El código en el constructor tampoco debería depender de cuándo (esto está relacionado con las dependencias pero no exactamente igual) se ejecuta, pero puede suponer que se construirá al menos (justo antes se llama a un método) y C++ garantiza que el orden de destrucción es el inverso de la creación de instancias.

No es tan difícil cumplir con estas reglas.

2

C++ no define el orden que los inicializadores estáticos ejecutan para los objetos en diferentes unidades de compilación (el orden está bien definido dentro de una unidad de compilación).

Considere la situación en la que tiene 2 objetos estáticos A y B definidos en diferentes unidades de compilación. Digamos que el objeto B realmente usa el objeto A en su inicialización.

En este escenario, es posible que B se inicialice primero y realice una llamada en contra de un objeto A sin inicializar. Esto podría ser una cosa que significa "nada": un objeto se está utilizando cuando no ha tenido la oportunidad de inicializarse primero (incluso si se puede inicializar más tarde).

Supongo que la vinculación dinámica podría agregar complejidades que no he pensado en que un objeto nunca se inicialice. De cualquier manera, la conclusión es que initializatino estático presenta suficientes problemas potenciales que se deben evitar siempre que sea posible y se deben manejar con mucho cuidado donde se debe usar.

Cuestiones relacionadas