2009-09-08 29 views
9

Tengo la siguiente situación: Necesito crear un widget en la biblioteca estática independiente, que luego se vinculará con la aplicación final (visual C++ 9.0, qt 4.5). Esta biblioteca de widgets estáticos contiene algunos recursos (iconos) y consta de varios archivos .cpp (cada uno contiene un widget independiente). Por lo que sé, debo inicializar el sistema de recursos qt, si los uso (recursos) en la biblioteca estática, con la llamada a "Q_INIT_RESOURCE (resource_file_name)". He resuelto esto con el siguiente código (en cada archivo .cpp en la biblioteca estática):Inicializando recursos qt incrustados en la biblioteca estática

 

#include <QAbstractButton> 

namespace { 
struct StaticLibInitializer 
{ 
    StaticLibInitializer() 
    { 
     Q_INIT_RESOURCE(qtwidgets_custom_resources); 
    } 
}; 
StaticLibInitializer staticLibInitializer; 
} 

// ... widget code .... 
 

En lugar de mi primer acercamiento, he creado el archivo init.cpp separada en el proyecto de biblioteca estática con el código de inicialización (para evitar la inclusión de inicialización código en cada archivo .cpp), pero esto no funcionó.

¿Por qué esto no funcionó?

¿Este enfoque con StaticLibInitializer es seguro y portátil entre varios compiladores y plataformas?

Respuesta

10

No funcionó porque lograste ser golpeado por static initialization order fiasco.

No se puede mover el código que inicializa los objetos estáticos que exceden el tamaño de la unidad de traducción (puede leerlo como archivo fuente) donde se usan estos objetos estáticos. No de la manera en que lo hiciste Si desea utilizar el esquema que está utilizando para inicializar estos objetos estáticos, solo mueva las declaraciones al encabezado init.hpp pero deje las instancias StaticLibInitializer staticLibInitializer; en cada archivo que use objetos estáticos.
El consejo anterior asume que cada widget usa solo sus propios recursos. Si tiene una situación en la que los recursos de un widget son utilizados por otro widget, se ejecuta de nuevo fiasco de orden de inicialización estática. Usted puede manejar esta situación mediante el uso de un código como éste

StaticLibInitializer 
{ 
    void initialize() 
    { 
     static Q_INIT_RESOURCE(qtwidgets_custom_resources); 
    } 

    StaticLibInitializer() 
    { 
     initialize(); 
    } 
} 

para asegurarse de que se multiplican las instanciaciones de StaticLibInitializer inicializará recurso dado una sola vez y luego instanciar StaticLibInitializer para cada recurso que se va a utilizar en la unidad de traducción dado.

+0

En mi situación actual, tengo tres archivos .cpp (cada uno de ellos implementa su propio widget, dos de ellos usan recursos del archivo .qrc), pero el código de inicialización, que proporcioné en la pregunta original, solo en uno de ellos y todo funciona bien (100%, no 50/50). Entonces no puedo entender, ¿por qué cuando pongo el código de inicialización en init por separado?Archivo cpp No puedo usar mis recursos, pero cuando este código en uno de los archivos .cpp del widget funciona bien ... – cybevnm

+0

No importa que funcione bien ** ahora ** :) Funciona solo por accidente. Puede dejar de funcionar en el momento en que empiece a usar otro compilador o incluso otra versión del mismo compilador. Es ** COMPORTAMIENTO INDEFINIDO **. La razón por la que funciona ahora es porque cuando tienes el código de inicialización en uno de los archivos del widget, el compilador ** sucede ** para inicializar tus recursos primero. Pura suerte, nada más. Si no desea que su programa funcione 0% un día soleado, siga las instrucciones para evitar * fiasco de orden de inicialización estática *. –

+0

¿El orden de inicialización estático está definido por el compilador en la fase de compilación, o el orden puede variar entre reinicios de los programas (sin recompilación)? – cybevnm

6

La macro Q_INIT_RESOURCE no se puede utilizar en un espacio de nombres.

Permítanme citar del manual qt: "Nota: Esta macro no se puede utilizar en un espacio de nombre. Se debe llamar desde main()". E incluso le da un ejemplo de cómo hacer las cosas bien, si esto no es posible:

inline void initMyResource() { Q_INIT_RESOURCE(myapp); } 

    namespace MyNamespace 
    { 
    ... 

    void myFunction() 
    { 
     initMyResource(); 
    } 
    } 

Por favor ven por qué y cómo es exactamente lo que falla o no falla si se utiliza de una manera no especificada. El código relevante está en QtCore.

+0

Pero en el primer enfoque (cuando incluyo el código en cada archivo .cpp de la biblioteca estática) funciona (incluso con el espacio de nombres anónimo). – cybevnm

+0

El uso de 'inline' de arriba no le compra nada ya que no tiene garantía de que sea respetado por un compilador. * No * respetando esta palabra clave está de acuerdo con el estándar C++. Entonces, si esta * solución * se basa en el supuesto de que la función en línea estará en línea, está rota. –

+1

funciones 'en línea' tienen una semántica ligeramente diferente, especialmente cuando se trata de la ODR. Teniendo en cuenta que no conocemos la macro expansión de 'Q_INIT_RESOURCE' en todas las plataformas, es difícil juzgar si es necesario. Ciertamente es razonable ponerlo allí. – MSalters

Cuestiones relacionadas