2012-02-01 17 views
5

Sto compilando una libreria condivisa con due unità di compilazione: globals.cpp e stuff.cpp. Il file globals.cpp inizializza una manciata di variabili esterne utilizzate in stuff.cpp. Il problema che sto verificando è che il codice in stuff.cpp è in esecuzione prima che il codice in globals.cpp abbia avuto l'opportunità di assegnare un valore alle variabili esterne. Ad esempio, sto vedendo un gruppo di valori 0 utilizzati. Questo problema dipende da quale piattaforma compilo/eseguo il codice, alcuni funzionano e altri no.Perché la mia variabile extern non è ancora inizializzata?

Come si può risolvere? Posso forzare lo a eseguire prima?

+3

Si sta verificando il [fiasco dell'ordine di inizializzazione statico] [1]. [1]: http://stackoverflow.com/questions/3035422/static-initialization-order-fiasco – kfmfe04

+0

Grazie, questo chiarisce almeno il problema. – sholsapp

risposta

6

Non si può (in modo coerente)

Ma si può lavorare intorno ad esso.

global.cpp

// If you have a global variable that has to be initial by a constructor 
MyObj globalX; 

// Instead do this 

MyObj& globalX() { static MyObj x; return x;} 

Hai ancora una variabile globale. Ma mettendolo in una funzione sappiamo quando viene utilizzato. Usando un membro statico della funzione esso viene inizializzato la prima volta che viene chiamata la funzione ma non dopo. Quindi sai che sarà costruito correttamente prima del primo utilizzo.

+0

Questo ha risolto il problema. – sholsapp

2
+0

Come al solito le FAQ danno un cattivo consiglio. L'uso di puntatori indica che gli oggetti non sono costantemente distrutti e il punto successivo sui problemi con l'ordine di distruzione è semplicemente sbagliato: http: // StackOverflow.it/questions/335369/finding-c-static-initialization-order-problems # 335746 –

+0

@LokiAstari: interessante. È completamente sbagliato? La FAQ menziona "Se i costruttori di a, be c usano ans, dovresti normalmente stare bene poiché il sistema di runtime, durante la deinitializzazione statica, distruggerà le ans dopo che l'ultimo di quei tre oggetti è stato distrutto.", Anche se sono d'accordo che non dovrebbe essere così sprezzante. – jamesdlin

+0

Respinge le perdite non come un problema perché la memoria viene ripulita dal sistema operativo. Questo è solo ** sciatto e BAD **. Qualunque cosa abbia un costruttore/distruttore, allora non è proprio la memoria; riguarda le risorse che questi oggetti detengono e la loro pulizia. Ci potrebbe essere qualsiasi cosa in questi oggetti e quando modifichi un oggetto controlli tutti i posti che stai '' 'probabilmen- te perdite '' per assicurarti che la perdita non influenzi la correttezza dei tuoi codici (suppongo che non potresti nemmeno trovare questi posti). Quindi l'unica volta che il suo commento è rilevante è per cose senza costruttore/distruttore. –

0

Sto assumendo che state vedendo questo behavious perché si sta facendo in linea di inizializzazione delle variabili globali senza una chiamata di funzione esplicita. per esempio. globals.cpp:

// top of source file 

#include "myincludes.h" 

CSomeClass someObject(432); 
int global_x = 42; 
int global_y = InitY(); 

Il costruttore e distruttore ordine degli oggetti globali e ordine globale inizializzazione delle variabili è per lo più non-deterministico. (Direi, senza consultare le pagine di riferimento standard, che le variabili in un file sorgente vengano inizializzate dalla prima dichiarazione in basso, ma l'ordine di "quale file sorgente viene prima" non è definito.)

La soluzione migliore è non avere oggetti globali (dove il costruttore viene eseguito prima di qualsiasi funzione nella libreria) o avere una dipendenza dall'ordine di inizializzazione delle variabili globali.

Meglio disporre di una funzione che inizializza in modo esplicito la libreria. Forse hai bisogno che l'app chiami questa funzione all'avvio o le funzioni esportate della tua libreria lo chiamino dopo aver rilevato che l'inizializzazione non è avvenuta. Inizializza quindi i tuoi globali.

Nella mia squadra, il codice che viene eseguito prima di "main" (o "DllMain") è severamente vietato. In altre parole, nessun oggetto globale. Nessuna funzione per avviare globals.

Problemi correlati