2009-03-11 4 views
5

In C++, si supponga di voler dichiarare una variabile globale che deve essere utilizzata da molti. Come si fa?Qual è il modo migliore per dichiarare una variabile globale?

In genere uso dichiarare e definire nel file cpp, quindi utilizzare extern in altri file cpp (e non nelle intestazioni).

Non mi piace questo approccio, e sto considerando qualcosa in questo senso:

In un file di intestazione:

some_file.h

Class MYGlobalClass 
{ 

}; 


MyGlobalClass& MyGlobalClassInstance() 
{ 
    static MYGlobalClass instance; 
    return instance; 

} 

Modifica

Considerare nei seguenti contesti:

  • può essere utilizzato in applicazioni multi-threaded
  • inquinamento namespace
  • potrebbero non necessery essere un Singleton, come molti esempi di questo potrebbero essere create

Quali sono i tuoi pensieri, suggerimenti, nuove idee?

+0

Modello di progettazione Singleton –

+0

Non è una buona idea, guarda i commenti sotto –

+0

Una variabile globale, di cui vuoi creare più istanze? Sembra che tu debba ancora elaborare un po '... – Reunanen

risposta

2

dichiararlo in un unico file di intestazione (usando extern), e definirlo in (o qualunque altra estensione) del file uno.cpp. È possibile utilizzare una funzione e restituire un riferimento a una variabile statica come si è mostrato per aggirare i problemi con un ordine di costruzione relativo ad altre variabili dello scope dei nomi in altri file .cpp. Ma ricorda che non ti proteggerà dai problemi di ordine di distruzione - che è esattamente nell'ordine inverso dalla costruzione (queste cose sono chiamate "fiasco di inizializzazione statica". Se usi una funzione come la tua e la metti nelle intestazioni, rendila in linea per rendere valida la ridefinizione della funzione quando è inclusa in più file .cpp (logicamente, la funzione è ancora solo apparente una volta, poiché la statica in essa esisterà solo una volta, non separatamente per ogni file in cui è inclusa). dichiararlo in un'intestazione ma definirlo in uno.cpp file (ma poi rimuovere l'inline da esso!).

inline A& getA() { static A a; return a; } 

I potenziali problemi con ordine di distruzione possono essere aggirate utilizzando new:

inline A& getA() { static A *a = new A; return *a; } 

Il distruttore di esso, tuttavia, non sarà mai chiamato allora. Se hai bisogno di sicurezza dei thread, dovresti aggiungere un mutex che protegge da accessi multipli. boost.thread probabilmente ha qualcosa per quello.

+0

qual è il problema con l'ordine di distruzione? – yesraaj

+0

è l'esatto ordine inverso di costruzione. Ad esempio, se un oggetto viene creato prima di chiamare getA() la prima volta, verrà distrutto dopo l'oggetto in getA(). I.e c'è un ordine particolare. Se per esempio accedi a getA() nel distruttore di oggetti, accederai a un riferimento ciondolante. –

+0

cerca "fiasco di inizializzazione statica" e penso che troverai una spiegazione (più lunga della mia breve panoramica qui, ovviamente) di quella stranezza. –

0

extern MyGlobalClass MyGlobalClassInstance;

Modifica: non statico>. <

+0

statica non funzionerà, ho bisogno di condividerla su file, moduli o anche su librerie. grazie per il tuo tempo anche se –

4

dichiarare come extern in un unico file di intestazione incluso da "molti" e definirlo in un unico file * cpp

+0

Buona idea! forse definire una funzione in linea nel file di intestazione? e includere l'intestazione da molti? –

+0

Nessuna scuola come la vecchia scuola. – chaos

1

dichiarare e definire in un file cpp

ottenere la dichiarazione -ed extern in un colpo di testa. Definirlo solo una volta in un file di implementazione.

Sei vicino. Utilizzare invece uno spazio dei nomi per le variabili globali.

namespace myns { 
    int foo = 0; 
} 

Ora, se si tratta di un oggetto di classe, si sta osservando il modello Singletion. Infatti, il codice di esempio riflette un design Singleton. Tuttavia, se si intende definire la funzione nell'intestazione, renderla in linea - Violazione ODR in caso contrario.

+0

Ho considerato namespace .... –

+0

Stai pensando ad un oggetto Singleton. In tal caso avere un accessorio e usarlo. Certo, è ancora necessario includere l'intestazione. Date un'occhiata.http: //en.wikipedia.org/wiki/Singleton_pattern – dirkgently

+0

Grazie, ho familiarità con Singleton. Tuttavia, NON è la soluzione che sto cercando. –

-1

Perché non utilizzare il buon vecchio modello singleton?

+0

Perché aggiunge solo nuovi problemi, e non risolve quello che ha bisogno di risolvere – jalf

+0

Non voglio solo una istanza di quella classe! più un overhead inutile –

+0

Ma il codice che hai scritto è un singleton con esattamente un'istanza statica !! –

2

L'idea di una statica all'interno della funzione di accesso è significativamente diversa da una variabile globale. La differenza è quando è costruita, ed è più probabile che sia un grosso problema con più thread. Cosa succede se due thread chiamano allo stesso tempo MyGlobalClassInstance? A seconda dell'ambiente, ma sospetto che questo sia tipico della maggior parte dei compilatori C++, è possibile ottenere due chiamate al costruttore di MyGlobalClass in esecuzione contemporaneamente, indirizzando la stessa area di memoria.

Se si è a thread singolo, è meno probabile che si tratti di un problema.

Se si dichiara l'istanza come membro statico normale o come normale variabile globale nel file di origine, sarà probabilmente più semplice, poiché il costruttore verrà chiamato prima dell'esecuzione di main, prima di avere la possibilità di inizia altri thread.

+0

D'altra parte, se si dichiara una variabile globale semplice, si ottengono tutti i problemi con un ordine di inizializzazione imprevedibile. – jalf

+0

Sì. C++ non è una cagna ?! :) –

+0

sì :) (10 caratteri padding) – jalf

1

E 'veramente una variabile globale che potrebbe teoricamente accessibile esternamente da qualsiasi modulo, si dovrebbe mettere la dichiarazione extern nel file di intestazione:

// MyClass.h 
class MyClass { ... }; 
extern MyClass myGlobalInstance; 

// MyClass.cpp 
MyClass myGlobalInstance; 

Se è solo un oggetto globale che in realtà dovrebbe essere accessibile solo da un singolo modulo, limitane l'ambito rendendolo una variabile di classe statica privata (o protetta), una variabile di funzione statica (se è necessaria solo da una funzione) o in uno spazio dei nomi anonimo:

Opzione 1:

// MyClass.h 
class MyClass 
{ 
private: // or protected, if you want it accessible by subclasses 
    static MyClass myGlobalInstance; 
}; 

Opzione 2:

// MyClass.cpp 
void someFunction() 
{ 
    // it's global, but only accessible inside this function 
    static MyClass myGlobalInstance; 
    ... 
} 

Opzione 3:

// MyClass.cpp 
namespace 
{ 
    MyClass myGlobalInstance; 
} 

// it's now only accessible in this file 
10

Il miglior consiglio è probabilmente "cercare di evitare globali". Le persone non hanno bisogno di variabili globali tutte le volte che pensano. Di solito si scopre che "passare tutto come argomenti ai costruttori" non è tanto un lavoro come le persone pensano quando ascoltano il suggerimento. Inoltre, tende a condurre a un codice più pulito con meno e più esplicite dipendenze.

Non sono a conoscenza di alcun modo "corretto" per dichiarare globali in C++. Il modo in cui lo fai ora funziona bene, ma l'ordine di inizializzazione non è specificato, quindi se ci sono delle dipendenze tra le tue globali, sei nei guai.

Una funzione che restituisce un'istanza statica più o meno risolve tale problema, ma non è thread-safe.

E un singleton è solo una pessima idea. Non risolve il tuo problema, ma aggiunge ulteriori vincoli al tuo codice, che in realtà non erano necessari, e molto probabilmente torneranno e ti morderanno in seguito.