2009-09-08 9 views
9

Ho una situazione successiva: ho bisogno di creare widget nella libreria statica autonoma, che sarà quindi collegata all'applicazione finale (visual C++ 9.0, qt 4.5). Questa libreria di widget statici contiene alcune risorse (icone) e consiste di diversi file .cpp (ognuno contiene un widget autonomo). Per quanto ne so, devo inizializzare il sistema di risorse qt, se li uso (risorse) nella libreria statica, con la chiamata a "Q_INIT_RESOURCE (resource_file_name)". Ho risolto questo con codice successivo (in ogni file cpp nella libreria statica):Inizializzazione delle risorse qt incorporate nella libreria statica

 

#include <QAbstractButton> 

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

// ... widget code .... 
 

invece del mio primo approccio, ho creato il file init.cpp separata nel progetto di libreria statica con codice di inizializzazione (per evitare di includere l'inizializzazione codice in ogni file .cpp), ma questo non ha funzionato.

Perché questo non ha funzionato?

Questo approccio con StaticLibInitializer è sicuro e portatile tra vari compilatori e piattaforme?

risposta

10

Non ha funzionato perché sei riuscito a essere colpito da static initialization order fiasco.

Non è possibile spostare il codice che inizializza gli oggetti statici in eccesso dell'unità di traduzione (è possibile leggerlo come file di origine) in cui vengono utilizzati questi oggetti statici. Non come l'hai fatto tu. Se si desidera utilizzare lo schema che si sta utilizzando per inizializzare questi oggetti statici piuttosto che spostare solo le dichiarazioni sull'intestazione init.hpp, lasciare gli instatiations StaticLibInitializer staticLibInitializer; in ogni file che utilizza oggetti statici.
Sopra consiglio assume che ogni widget utilizza solo le proprie risorse. Se si dispone di una situazione in cui le risorse di un widget sono utilizzate da un altro widget, si esegue nuovamente il fiasco dell'ordine di inizializzazione statico. È possibile gestire questa situazione utilizzando il codice come questo

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

    StaticLibInitializer() 
    { 
     initialize(); 
    } 
} 

per assicurarsi istanze moltiplicano di StaticLibInitializer inizializzare data risorsa sola volta e poi istanziare StaticLibInitializer per ogni risorsa che si sta per utilizzare in data unità di traduzione.

+0

Nella mia situazione attuale ho tre file .cpp (ognuno di loro implementa il proprio widget, due utilizzano risorse dal file .qrc), ma il codice di inizializzazione, che ho fornito nella domanda originale, solo in uno di essi e in tutti i lavori bene (100%, non 50/50). Quindi non riesco a capire, perché quando metto il codice di inizializzazione in init separato.cpp file Non posso usare le mie risorse, ma quando questo codice in uno dei file .cpp del widget funziona perfettamente ... – cybevnm

+0

Non importa, funziona bene ** ora ** :) Funziona solo accidentalmente. Può smettere di funzionare nel momento in cui inizi a utilizzare un altro compilatore o anche un'altra versione dello stesso compilatore. È ** COMPORTAMENTO NON DEFINITO **. Il motivo per cui funziona ora è perché quando si ha il codice di inizializzazione in uno dei compilatori di file del widget ** accade ** per inizializzare prima le risorse. Pura fortuna, niente di più. Se non vuoi far funzionare il tuo programma 0% un giorno di sole segui le istruzioni per evitare * l'ordine di inizializzazione statico fiasco *. –

+0

L'ordine di inizializzazione statico è definito dal compilatore in fase di compilazione, oppure l'ordine può variare tra i riavvii dei programmi (senza ricompilazione)? – cybevnm

6

La macro Q_INIT_RESOURCE non può essere utilizzata in uno spazio dei nomi.

Lasciatemi citare dal manuale qt: "Nota: questa macro non può essere utilizzata in un namespace. Dovrebbe essere chiamata da main()". E anche ti dà un esempio di come farlo nel modo giusto, se questo non è possibile:

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

    namespace MyNamespace 
    { 
    ... 

    void myFunction() 
    { 
     initMyResource(); 
    } 
    } 

Si prega di guardare te stesso perché e come esattamente si riesce o non fallisce se lo si utilizza in modo non specificato. Il codice rilevante è in QtCore.

+0

Ma nel primo approccio (quando includo il codice in ogni file .cpp della libreria statica) questo funziona (anche con namespace anonimo). – cybevnm

+0

L'uso di 'inline' sopra non ti compra nulla in quanto non hai alcuna garanzia che verrà rispettato da un compilatore. * Non * il rispetto di questa parola chiave è conforme allo standard C++. Quindi, se questa * soluzione * è basata sull'assunzione, la funzione inline sarà delineata è rotta. –

+1

Le funzioni 'inline' hanno una semantica leggermente diversa, specialmente quando si tratta dell'ODR. Considerando che non conosciamo l'espansione macro di 'Q_INIT_RESOURCE' su tutte le piattaforme, è difficile giudicare se è necessario. È certamente ragionevole metterlo lì. – MSalters

Problemi correlati