2010-03-03 8 views
6

Sto tornando in C++ dopo una lunga assenza e sto inciampando un po 'sulla mia comprensione del problema di inizializzazione statica abbastanza noto.Costing e inizializzazione C++ (c'è un fiasco)

Diciamo che ho una semplice classe Vector2 come indicato di seguito (notare che io sono consapevole che xey devono essere privato con getter e setter, questi sono appena stati omessi per brevità):

class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {}; 
    float x,y; 
} 

Ora , se voglio specificare un membro const statico per rappresentare un Vector2 con x e y impostato su 1, non sono sicuro su come procedere - i membri const statici non rispondono al problema di inizializzazione statica o l'atto di renderli const significa Loro sono ok? Sto giocando con l'seguenti possibilità:

Possibilità 1:

// .h 
class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {} 
    static const Vector2 ONE; 
    float x,y; 
}; 

// .cpp 
const Vector2 Vector2::ONE = Vector2(1.f, 1.f); 

Possibilità 2:

// .h 
class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {} 
    static const Vector2& getOne(); 
    float x,y; 
private: 
    static const Vector2 ONE; 
}; 

// .cpp 
const Vector2 Vector2::ONE = Vector2(1.f, 1.f); 

static const Vector2& Vector2::getOne() { 
    return ONE; 
} 

Possibilità 3:

// .h 
class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {} 
    static const Vector2& getOne(); 
    float x,y; 
}; 

// .cpp 
const Vector2& Vector2::getOne() { 
    static Vector2 one(1.f,1.f); 
    return one; 
} 

Ora, il mio modo preferito di scrivere questo sarebbe come nella possibilità 2, solo perché è una sintassi più comoda per me. Tuttavia, se chiamo il metodo getOne() da un altro metodo statico in un'altra classe, rischierò di andare in crash e di bruciare? Come ho detto, è perché sto usando un const statico piuttosto che un semplice statico che sto facendo questa domanda perché ho trovato molto sui problemi dei membri di una classe statica, ma nulla su problemi statici.

Ho il sospetto che non guadagno nulla dal fatto che sto usando const statico e che avrò bisogno di andare con la possibilità 3 per essere sicuro, ma voglio solo chiedere nel caso qualcuno possa far luce su questo per me.

Mi rendo conto che probabilmente mi sto aprendo a una serie di collegamenti che indicano esattamente quello che sto chiedendo, ma ho cercato e non ho trovato prima di postare questo.

Qualsiasi aiuto sarà apprezzato con gratitudine.

+0

Non è completamente chiaro dalla tua domanda, ma sei ** solo ** incline alla cosa fiasco se provi ad accedere al membro statico da * un altro inizializzatore statico * direttamente o meno. Accedendo da un'altra funzione statica o meno, dopo che main() è stato chiamato è OK – sbk

+0

Grazie per il tuo commento sbk. Avrei dovuto essere un po 'più chiaro nella mia domanda. La mia intenzione era di assicurare che stavo per essere sicuro che il membro statico fosse usato da un inizializzatore statico in un'altra classe in un file cpp separato. Sebbene nessuna delle mie altre classi attualmente utilizzi Vector2 :: getOne() specificamente per inizializzare un altro membro statico, ho casi in cui esiste una catena di inizializzatori statici. Ho scelto Vector2 come un semplice esempio in modo da poter capire dai commenti qui il miglior schema da applicare all'intero progetto. Mille grazie per il commento. –

risposta

10

Tutti, tranne la possibilità 3, soffrono del fiasco dell'ordine di inizializzazione statico. Questo perché la tua classe non è un POD. In C++ 0x, questo problema può essere risolto contrassegnando il costruttore constexpr, ma in C++ 03 non esiste tale soluzione.

È possibile rimuovere il costruttore di risolvere il problema in C++ 03, e inizializzare utilizzando

const Vector2 Vector2::ONE = { 1.f, 1.f }; 

Questo l'inizializzazione di un POD, e tutti gli inizializzatori nella lista sono espressione costante (a scopo di statica inizializzazione). La loro inizializzazione avviene prima che venga eseguito qualsiasi codice che possa accedervi prima di essere inizializzato.

3.6.2:

oggetti con durata di conservazione statica (3.7.1) sarà zero inizializzato (8,5) prima di qualsiasi altra inizializzazione avviene. Inizializzazione e inizializzazione zero con un'espressione costante vengono chiamate collettivamente inizializzazione statica; tutte le altre inizializzazioni sono l'inizializzazione dinamica. Gli oggetti di tipi POD (3.9) con durata di archiviazione statica inizializzata con espressioni costanti (5.19) devono essere inizializzati prima che avvenga l'inizializzazione dinamica.

8.5.1/14:

Quando un aggregato con durata di conservazione statica viene inizializzato con un inizializzatore-list brace-chiuso, se tutte le espressioni membro di inizializzazione sono espressioni costanti, e l'aggregato è un tipo POD, l'inizializzazione deve essere eseguita durante la fase statica di inizializzazione (3.6.2); in caso contrario, non è specificato se l'inizializzazione di membri con espressioni costanti avviene durante la fase statica o durante la fase dinamica di inizializzazione.

+0

Grazie per il tuo commento Johannes. Apprezzo che tu abbia il tempo di rispondere e per confermare le mie 3 possibilità il 3 è l'unico sicuro da usare. Non avevo pensato di seguire il percorso di inizializzazione del POD, quindi questo è molto istruttivo. Anche se ho classi più complesse in cui l'approccio del POD non funzionerà (poiché non tutte le mie classi possono essere trattate come POD) è comunque molto utile sapere come posso sicuramente vedere i posti in cui posso usare questo. Molte grazie –

+0

Ho appena realizzato che non avevo mai accettato la tua risposta. Ci scusiamo, ma rettificato ora, quasi un anno dopo –

1

Si prega di notare che la possibilità 3 non è thread-safe.

Vedere ad esempio "L'inizializzazione statica con ambito C++ non è thread-safe, apposta!" a http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx

+1

Si prega di notare che questa risposta non è più corretta: la sicurezza del thread è ora [imposta dallo standard] (http://stackoverflow.com/questions/8102125/is-local- statica variabile inizializzazione-thread-safe-in-C11) – Arnaud

Problemi correlati