"Unbekannter Softwarefehler" bei globaler Variable einer Templateklasse mit statischem Member



  • Folgendes Beispiel

    using namespace std;
    
    template<typename T>
    class foo
    {
    public:
    
    	foo()
    	{
    		v.push_back(this);
    	}
    
    	static vector<foo<T>*> v;
    };
    
    template<typename T>
    vector<foo<T>*> foo<T>::v;
    
    foo<int> f;
    
    int main()
    {
    }
    

    liefert mir (VS 2008) beim Starten den Fehler "Die Ausnahme "Unbekannter Softwarefehler" (0xc0000417) ist in der Anwendung an der Stelle 0x7858ccb5 aufgetreten.". Nach ein bisschen Debuggen fand ich heraus, dass das push_back fehlschlägt, konkreter ein return begin(); im durch push_back aufgerufenem insert . Ich vermute deshalb, dass v zum Zeitpunkt des Konstruktoraufrufes noch nicht vollständig konstruiert ist.
    Dieser Fehler tritt nur auf, wenn foo eine Templateklasse ist und f eine globale Variable. Ich war aber bisher der Meinung, dass statische Member vor dem Konstruktor konstruiert sind.

    Deshalb meine Frage: gibt es für dieses Verhalten einen Grund (im Standard festgelegt), mache ich eventuell etwas falsch, oder ist hier gar ein Bug im VS (andere Compiler konnte ich leider nicht testen)?



  • Dein Code läuft zumindest bei mir unter Visual Studio 2010.


  • Mod

    ipsec schrieb:

    Deshalb meine Frage: gibt es für dieses Verhalten einen Grund (im Standard festgelegt)

    Ja - d.h., das Verhalten ist potentiell undefiniert, weil die Reihenfolge der Instantiierung von f und foo<int>::v unspezifiziert ist.
    Siehe auch Order of initialization in instantiation units

    Obiger Code kann funktionieren, z.B. dann, wenn die Initialisierung von v statisch durchgeführt wird. Oder aber die Initilisierung passiert gerade zufällig in der gewünschten Reihenfolge.

    Jedenfalls müsstest du, um das gewünschte Verhalten mit Sicherheit zu erreichen, foo<int>::v zuvor explizit instantiieren.



  • Vielen Dank, camper, das beantwortet schon mal einiges. 🙂

    camper schrieb:

    Jedenfalls müsstest du, um das gewünschte Verhalten mit Sicherheit zu erreichen, foo<int>::v zuvor explizit instantiieren.

    Doofe Frage: wie mache ich das?


  • Mod

    ipsec schrieb:

    Vielen Dank, camper, das beantwortet schon mal einiges. 🙂

    camper schrieb:

    Jedenfalls müsstest du, um das gewünschte Verhalten mit Sicherheit zu erreichen, foo<int>::v zuvor explizit instantiieren.

    Doofe Frage: wie mache ich das?

    template vector<foo<int>*> foo<int>::v;
    


  • Eine Alternative wäre auch eine funktionslokale statische Variable, denn diese wird beim ersten Aufruf der Funktion initialisiert. Wenn die Funktion gar nie aufgerufen wird, fällt die Konstruktion von v weg.

    template<typename T>
    class foo
    {
    public:
        foo()
        {
            GetV().push_back(this);
        }
    
    private:
        static vector<foo<T>*>& GetV()
        {
            static vector<foo<T>*> v;
            return v;
        }
    };
    


  • Vielen Dank euch beiden.
    Die Variante mit der expliziten Instantiierung liefert bei mir leider den gleichen Fehler, aber Nexus' Idee gefällt mir sehr gut. Damit entfällt auch diese umständliche Syntax bei der Definition.


Anmelden zum Antworten