2012-04-04 13 views
3
// File: InitFirst.h 

#pragma once 

template <int val> 
struct InitFirst 
{ 
    static float s_dividedByThree; 
}; 

template <int val> 
float InitFirst<val>::s_dividedByThree = val/3.0; 

// File: Test.h 

#include <conio.h> 
#include <tchar.h> 

#include "InitFirst.h" 

float g_shouldBeOneThird = InitFirst<1>::s_dividedByThree; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    _cprintf("%f\n", g_shouldBeOneThird); 
    getch(); 
    return 0; 
} 

Ist g_shouldBeOneThird garantiert auf rund 0.333 initialisiert werden? Mit anderen Worten, wird das statisch initialisierte InitFirst < 1> :: s_dividedByThree garantiert initialisiert, bis es für die statische Initialisierung von g_shouldBeOneThird verwendet wird?Initialisierung Reihenfolge der statischen Daten innerhalb Klassenvorlage

Antwort

2

Von der Norm (3.6.2): ​​

Objekte mit statischer Speicherdauer (3.7.1) werden mit Null initialisiert (8,5) sein, bevor eine andere Initialisierung stattfindet. Eine Referenz mit statische Speicherdauer und ein Objekt vom POD-Typ mit statischem Speicher Dauer kann mit einem konstanten Ausdruck (5.19) initialisiert werden; Dies ist genannt konstante Initialisierung. Zusammen werden Null-Initialisierung und Konstanten Initialisierung statische Initialisierung genannt; Alle anderen Initialisierung ist dynamische Initialisierung. Die statische Initialisierung soll durchgeführt werden, bevor eine dynamische Initialisierung stattfindet. Dynamische Initialisierung eines Objekts ist entweder geordnet oder ungeordnet. Definitionen von explizit spezialisierten statischen Daten der Klassenvorlage Mitglieder haben die Initialisierung angeordnet. Andere statische Klassen-Template-Daten Mitglieder (d. H. Implizit oder explizit instanziierte Spezialisierungen) haben eine ungeordnete Initialisierung. Andere im Namespace definierte Objekte haben die Initialisierung angeordnet. Objekte, die in einer einzigen Übersetzungseinheit definiert sind und eine geordnete Initialisierung haben, müssen in der Reihenfolge ihrer Definitionen in der Übersetzungseinheit mit initialisiert werden. Die Reihenfolge der Initialisierung ist für Objekte mit ungeordneter Initialisierung und für Objekte, die in verschiedenen Übersetzungseinheiten definiert sind, nicht spezifiziert.

In Ihrem Fall hier, da Sie float InitFirst<val>::s_dividedByThree mit einem konstanten Ausdruck sind initialisiert, das vor jeder dynamischen Initialisierung passieren wird (f.x float g_shouldBeOneThird). Obwohl ich das Gefühl habe, dass dieses vereinfachte Beispiel eine Vereinfachung eines Falles mit dynamischer Initialisierung sein könnte, ist der relevante Teil: "Objekte, die innerhalb einer einzelnen Übersetzungseinheit und mit geordneter Initialisierung definiert sind, müssen in der Reihenfolge ihrer Definitionen in der Übersetzungseinheit. "

Es gibt einen Trick, um sicherzustellen, dass globale Variablen (Art) initialisiert werden, wenn Sie sie verwenden. Der Trick besteht darin, sie als statische lokale Variable in einer globalen Funktion zu behalten. Da lokale statische Variablen zum ersten Mal initialisiert werden sie zugegriffen wird, Initialisierung, um kein Thema mehr ist:

template <int val> 
struct InitFirst 
{ 
    static float & s_dividedByThree(); 
}; 

template <int val> 
float & InitFirst<val>::s_dividedByThree(){ 
    static float staticVariable = val/3.0; 
    return staticVariable; 
} 

können Sie dann diese Variablen zugreifen fast wie zuvor:

float g_shouldBeOneThird = InitFirst<1>::s_dividedByThree(); 

obwohl Vorsicht Initialisierung von lokalen statischen Variablen ist nicht sicher unter mehreren Threads (es ist nicht im Standard, dass sie sicher sein sollten). Wenn das ein Problem für Sie ist, möchten Sie möglicherweise die Initialisierungen mit einige Sperren schützen. Den Compilern ist es natürlich erlaubt, sicheren Code zu erzeugen, was gcc standardmäßig tut (wahrscheinlich auch andere).

+0

Ich habe nicht downvote, aber ich glaube, der letzte Teil ist falsch (von * Allerdings * auf) und das ist, was mich davon abhält, zu verbessern ... –

+0

@ DavidRodríguez-dribeas Sie haben absolut Recht, ich habe immer sonst angenommen. Dies erklärt auch, warum statische Member von Vorlagenklassen eine ungeordnete Initialisierung aufweisen. Der Linker könnte sie beim Zusammenklappen der Vorlageninstanzen beliebig platzieren. – enobayram

+0

@enobayram Sie haben richtig geraten, mein aktueller Code verwendet keine const-Ausdrücke, um die Daten zu initialisieren, daher wäre die Initialisierung dynamisch. Und wenn ich mich richtig versehe, wäre die Reihenfolge der Initialisierung und damit das Verhalten meines Programms unspezifiziert. – zeroes00

Verwandte Themen