Static initalization order fisco



  • Hallo, ich habe ein Problem mit static. Der Code:

    A.h:

    #include "B.h"
    class A
    {
    public:
    	A();
    	static std::map<std::wstring, Object*> values;
    };
    

    A.cpp:

    std::map<std::wstring, Object*> A::values;
    bool registered = B::Register();
    

    B.h:

    class B
    {
    public:
    	B();
    	static bool Register();
    };
    

    B.cpp:

    bool B::Register()
    {
    	std::map<std::wstring, Object*> copy = A::values;
    	return true;
    }
    

    Beim Programmstart bekomme ich die Meldung dass die Anwendung nicht korrekt gestartet werden konnte (0xc0000005). Der Fehler tritt bei folgendem Aufruf

    std::map<std::wstring, Object*> copy = A::values;
    

    innerhalb der Register-Funktion auf. Ich vermute dass warum auch immer zu diesem Zeitpunkt die statische std::map values noch nicht initalisiert wurde. Aber warum?
    Kann das evtl mal jemand (mit Visual Studio 2010) testen? Ich kompiliere den Code zu einer DLL.

    Gruß
    Student83



  • So habe aus dem Code ein Minimalbeispiel gemacht. Ich versuche also in der statischen Funktion Register von Klasse B auf die statische map von Klasse A zuzugreifen, was nicht geht.



  • Hi,

    wenn du dir unsicher bzgl. der Initialisierungsreihenfolge bei statischen Objekten bist,
    dann mach eine Funktion daraus. Die garantiert die rechtzeitige Initialisierung:

    std::map<std::wstring, Object*>& getValues()
    {
      static std::map<std::wstring, Object*> values;
      return values;
    }
    


  • Tatsächlich habe ich das so gemacht, allerdings in dem Beispiel wegen der Übersichtlichkeit weggelassen.
    Ich habe auch gerade gemerkt dass ich mich selber veräppelt habe. Der obige Code verursacht gar keinen Fehler. Der Fehler tritt vielmehr auf wenn jetzt noch eine Klasse C ins Spiel kommt:

    Hier nochmal A.h:

    #include "B.h"
    class A
    {
    public:
        A();
        static std::map<std::wstring, Object*> GetValues();
    protected:
        static B keyProperty;
        static std::map<std::wstring, Object*> values;
    };
    

    A.cpp:

    std::map<std::wstring, Object*> A::values;
    B A::keyProperty = B::Register(); // geht!
    

    C.h:

    #include "A.h"
    class C : public A
    {
    public:
        C();
    protected:
        static B widthProperty;
    };
    

    C.cpp:

    B C::widthProperty = B::Register(); // geht nicht!
    

    Das keyProperty von Klasse A kann also mit der Register-Funktion initalisiert werden. Das widthProperty der Klasse C (die von A abgeleitet ist) dagegen nicht. Woran kann das liegen?



  • Doch nicht ;).



  • Also ich habe mal ein kleines Demoprogramm geschrieben das den Fehler verdeutlichen sollte:

    http://rapidshare.com/files/453561392/Test.rar

    Dazu müsst ihr nur den Pfad für die Library in der Main.cpp anpssen. Damit sollte das Programm funktionieren. Damit der Fehler auftritt müsst ihr in der Control.h die Zeile

    //static Property widthProperty;
    

    und in der Control.cpp die Zeile

    //Property Control::widthProperty = Property::Register();
    

    auskommentieren.
    Interessanter Weise tritt der Fehler nur auf wenn ich die DLL bzw. Lib verwende. Füge ich die Dateien aus dem DLL-Projekt zum Test-Projekt hinzu funktioniert es. Brauche ich vielleicht einfach noch irgendeine Einstellung im DLL-Projekt damit es läuft?



  • Niemand eine Idee? Könnte es an der Initialisierungsreihenfolge liegen? Manchmal bekomme ich auch einen Fehler in der xtree Datei Zeile 321 angegeben weil map/set iterators incompatible sind.



  • warum ist eigentlich so ziemlich alles static im baspielcode?
    wäre auch schön wenn beispiele etwas globaler halten könntest damit sie auch jeder kompilieren kann.

    was sollhier pasieren?

    Property Property::Register()
    
    {
    
    	std::map<std::wstring, int>::iterator it = Object::GetValues().find(L"Unfindbar");
    
    	return Property();
    
    }
    

    was soll den zurückgegeben werden?

    was genau hast du denn vor?

    du versuchst Property Object::keyProperty (der klasse Objects) über die methodeProperty::Register() zu initialisieren, die aber erst in Objects suchen muss.



  • Dass alles static ist liegt daran, dass ich mit dieser Methode bis zu 90% an Arbeitsspeicher einsparen kann, da fast alle Properties der Klassen ihre defaultwerte behalten. Microsoft macht das übrigens mit den DependencyProperties genauso. Ich versuche nun dies in C++ zu implemetieren.
    Ich weis jetzt auch woran es liegt. An der Initalisierungsreihenfolge. Wenn ich die values map aus der Klasse Object in der Control.cpp anstatt in der Object.cpp initalisiere funktioniert es. Allerdings ist das keine Lösung da die Vererbunghierarchie nicht linear sondern eine Baumstruktur hat. Ich müsste jetzt irgendwie erreichen können dass die values map aus der Object-Klasse als aller erstes initialisiert wird vor allem anderen. Gibt es da eine Möglichkeit zu?

    was sollhier pasieren?
    

    Das ist natürlich nicht der eigentlich Funktionscode. Ich wollte hier nur zeigen dass dieser Aufruf zu einem Fehler führt.



  • @Jockelx
    Da schreibst du schon die Lösung und ich verstehe es nur nicht :). Bei mir ist irgendwie nicht angekommen dass ich die Variable komplett durch die Funktion ersetzen soll. Ich habe die Variable noch weiter verwendet.

    Leider funktioniert das ganze so auch nicht, wahrscheinlich müsste ich alle statischen Member in Funktionen umwandeln nicht nur die Map.
    Allerdings erkauft man sich so ja ein neues Problem nämlich ein static deinitialization order fiasco. Was haltet ihr dagegen von der Schwarz Counter / Nifty Counter Methode wäre das die bessere Lösung für mein Problem? Allerdings will ich nur ungern für jede Klasse einen Initialisierer schreiben müssen.
    C++ ist wie eine Wundertüte (im schlechten Sinne). Jede Woche aufs neue muss ich feststellen dass die Dinge die mir C++ anbietet nicht funktionieren. Wozu gibt es dann eigentlich static wenn man es nicht verwenden kann?

    Kann man eigentlich sagen dass wenn man Thread-Safe programmieren möchte, komplett auf static verzichten muss?


Anmelden zum Antworten