Reihenfolge für Initialisierung statischer Objekte



  • Hallo zusammen,

    ich habe ein 2 Klassen mit jeweils einem statischen Objekt.
    Die eine Klasse erbt von der anderen.

    Bisher dachte ich, dass das statische Objekt der Basisklasse zuerst initialisiert
    wird, allerdings ist das bei mir (glaube ich) nicht der Fall 😞
    Kann ich die Initialisierungsreihenfolge beeinflussen?
    Es sollen allerdings 2 Dateien bleiben und die Basisklasse weiß nichts von der anderen.

    Gruß,
    CSpille



  • Nein. Die Reihenfolge der Initialisierung von statischen Varibalen ist undefiniert. Kann es sein, dass Dein Klassendesign irgendwie suboptimal ist? Was willst Du machen?



  • Ich hab ne Klasse mit rein virtuellen Funktionen und eine Methode
    getInstance().

    Je nach Betriebssystem möchte ich dann die betriebssystemspezifischen
    Klassen mitkompilieren.

    Dazu wollte ich instance mit 0 initialisieren und mit dem statischen Objekt einer
    HelferKlasse setze ich dann die Variable instance auf ein Objekt dieser abgeleiten
    Klasse.

    Mein erster Ansatz war die Initialisierung der instance in der .cpp der abgeleiteten Klasse
    zu machen. Fand ich aber nicht so gut, da es ja eigentlich zur Basisklasse gehört.

    Nach Möglichkeit eine Makrofreie Lösung 😉

    thx, schon einmal im Voraus 🙂

    Gruß,
    CSpille



  • Das alte Singleton Problem.
    Such nach Singleton, da findest du haufenweise Threads zu dem Thema. Bloss leider keine allgemeingültigen Antworten.



  • Hallo hustbaer,

    vielen Dank für den Hinweis, auch wenn ich jetzt noch keinen passenden
    Beitrag gefunden habe. Mir ist klar, dass ich durch Singleton die Reihenfolge
    beeinflussen kann, doch ich kann in meiner Klasse kein Objekt der anderen Klasse
    erstellen. Ausnahme per Makro. Und ich glaube darauf läuft es hinaus...

    Ich kuck mir das morgen nochmal an...

    Gute Nacht,
    CSpille



  • Wenn deine Singletons alle Lazy implementiert sind (von der Art "if (!instance) instance = new Singleton; return *instance;") sollte das doch kein Problem sein, oder?

    Abgesehen davon, Laufzeitpolymorphismus (also virtuelle Funktionen) solltest du nicht für eine solche Sache verwenden. Wenn das ganze plattformabhängig ist, dann ist bereits beim Kompilieren klar, welche Funktionen aufgerufen werden müssen. Du könntest für verschiedene Plattformen verschiedene Implementierungen der Funktionen benutzen (verschiedene .cpp-Dateien, die dann per Makefile oder womit auch immer du bauen willst ausgewählt werden).



  • Für statische Variablen innerhalb statischer Funktionen gilt: Sie werden vor dem ersten Aufruf der statischen Funktion initialisiert. 😉

    CBluber * s_pBluber;
    
    CBluber * GetStatischesBluber ()
    {
      static bool bInit = false;
      if (!bInit)
      {
        pBluber = new CBluber ();
        bInit   = true;
      }
      return s_pBluber;
    }
    

    Wird immer GetStatischesBluber () zum Zugriff auf s_pBluber aufgerufen ist s_pBluber immer initialisiert....



  • TempMathias schrieb:

    Für statische Variablen innerhalb statischer Funktionen gilt: Sie werden vor dem ersten Aufruf der statischen Funktion initialisiert. 😉

    Eben aufgrund dieser Regel kann man sich dann auch noch den Zeiger sparen. Dann kann man dem Kind auch noch den Namen Meyers-Singleton geben, den Konstruktor privat machen und GetStatischesBluber befreunden, dann ist sogar sichergestellt, dass immer GetStatischesBluber zum Zugriff auf bluber aufgerufen wird.

    CBluber & GetStatischesBluber ()
    {
      static CBluber bluber;
      return bluber;
    }
    


  • TempMathias schrieb:

    Wird immer GetStatischesBluber () zum Zugriff auf s_pBluber aufgerufen ist s_pBluber immer initialisiert....

    Und um das sicherzustellen, solltest du s_pBluber gar nicht frei in den Raum stellen:

    CBluber& GetStatischesBluber ()
    {
      static CBluber s_Bluber;
      return s_Bluber;
    }
    

    (beim ersten Aufruf der Funktion wird die statische Variable initialisiert und anschließend bei jedem Aufruf eine Referenz auf DIESE Variable geliefert)



  • a.) Es ging mir an der Stelle um das statische Objekt, nicht um einen
    Singelton. Natürlich läßt sich dies auch für einen Singelton verwenden.
    🤡
    b.) Das Zurückgeben einer Referenz auf eine statisches Objekt innerhalb einer
    statischen Funktion war auch meine erste Idee.
    Läßt sich auch wunderbar übersetzen. Es führte jedoch zumindest bei mir
    während der Laufzeit zu Abstürzen.
    Die Version mit dem Pointer hingegen arbeitet zuverlässig.



  • MathiasTemp schrieb:

    b.) Das Zurückgeben einer Referenz auf eine statisches Objekt innerhalb einer
    statischen Funktion war auch meine erste Idee.
    Läßt sich auch wunderbar übersetzen. Es führte jedoch zumindest bei mir
    während der Laufzeit zu Abstürzen.
    Die Version mit dem Pointer hingegen arbeitet zuverlässig.

    Kaputter Compiler?

    Ich benutze diese Technik in meinen Programmen zuhauf, und hatte noch nie derartige Probleme.



  • MathiasTemp schrieb:

    b.) Das Zurückgeben einer Referenz auf eine statisches Objekt innerhalb einer
    statischen Funktion war auch meine erste Idee.
    Läßt sich auch wunderbar übersetzen. Es führte jedoch zumindest bei mir
    während der Laufzeit zu Abstürzen.
    Die Version mit dem Pointer hingegen arbeitet zuverlässig.

    Und wie äußerte sich dieser Absturz?

    Die Lösung, wie du sie vorgestellt hast, hat auf jeden Fall einen Nachteil - s_pBluber ist global bekannt und damit könnte auch jemand auf die Idee kommen, es direkt (und uninitialisiert) zu verwenden.



  • War nur für das Beispiel... in meinem Quellcode habe ich das über einen Autopointer innerhalb einer statischen Klassenfunktion gelöst und eine Referenz
    auf das Objekt zurückgeliefert.

    Hmmm mein Mechanismus ist an der Stelle etwas aufwendiger. Meine statischen Funktionen sorgen quasie selbst dafür, dass sie einmal beim Programmstart aufgerufen und dabei die Objekte in einem globalen Container eingetragen werden.
    Wenn ich mich recht entsinne lags daran. 🙂



  • Und wie haben sie dafür gesorgt? Mir fällt da als "Lösung" nur ein, diese Initialisierungsfunktionen aus dem Ctor eines globalen Objekts aufzurufen - und damit stehst du wieder ganz am Anfang, weil du die Reihenfolge nicht kontrollieren kannst, in der die Objekte erzeugt werden.



  • Das Reihenfolge-Problem tritt deswegen nicht auf, weil auch der Container über eine statische Funktion mit Initialisierung angesprochen wird.



  • Häh? Zeig das doch mal mit etwas Code. (entweder du arbeitest mit lokalen statischen Variablen, dann mußt du die zugehörige Funktion selber in Gang setzen - oder du arbeitest mit globalen Objekten, die automatisch initialisiert werden (aber in undefinierter Reihenfolge))



  • Ist doch gar nicht so kompliziert.

    Durch die statischen Funktionen ist garantiert, das alle betroffenen statischen Objekte bereits bei der Initialisierung des ersten statischen Objekts zugreifbar sind.

    Und spätestens wenn die letzte globale Variable initialisiert wird, ist der
    Container vollständig gefüllt.

    😃



  • Und wer sorgt dafür, daß die statischen Funktionen in der richtigen Reihenfolge aufgerufen werden? ('static' bei einer Funktion bedeutet nicht automatisch, daß sie vor der main() einmal aufgerufen wird)

    Wie gesagt, zeig mal etwas Code, damit man sich deine Lösung vorstellen kann.



  • Keine der statischen Funktionen wird von main() aus aufgerufen. Das ist ja der Witz bei der ganzen Sache.

    Das Füllen des Containers erfolgt dezentral beim Initialisieren der statischen Variablen und die Reihenfolge spielt im ersten Schritt keine Rolle, hauptsache der Container ist da.. was ja durch die statische Funktion gegeben ist.

    Ich gehe an der Stelle noch ein bißchen weiter und baue eine Baumstruktur auf. Die Blätter rufen dann jeweils die statische Funktion der Knoten auf und initialisieren somit alle übergeordneten Knoten, falls diese noch nicht vorhanden sind.
    Somit trägt jedes Blatt alle übergeordneten noch nicht eingefügten Knoten mit ein.

    Quellcode gibt es leider nicht, weil ich diesen erst zensieren müsste und das ist mir zu viel Aufwand.



  • MathiasTemp schrieb:

    Keine der statischen Funktionen wird von main() aus aufgerufen. Das ist ja der Witz bei der ganzen Sache.

    Das Füllen des Containers erfolgt dezentral beim Initialisieren der statischen Variablen und die Reihenfolge spielt im ersten Schritt keine Rolle, hauptsache der Container ist da.. was ja durch die statische Funktion gegeben ist.

    Du hast einen globalen vector<> und jede globale Variable trägt sich per push_back() o.ä. in diesen vector ein, habe ich das jetzt soweit erfasst? Wie stellst du da sicher, daß der vector vor den anderen Variablen angelegt wird? Und wie schafft es dieser vector, weitere Initialisierungen in einer vordefinierten Reihenfolge ablaufen zu lassen?

    PS: Wenn dir dein Produktivcode zu umfangreich oder zu persönlich ist, begnpge ich mich auch mit einem gekürzten Psuedocode 😉



  • Na der Container steckt auch wieder in einer statischen Funktion. 😃

    CMengeGeblubber & GetMengeGeblubber ()
    {
      static CMengeGeblubber s_MengeGeblubber;
      return s_MengeGeblubber;
    }
    
    CGebluber & GetGebluberA ()
    {
      static CGeblubber s_GeblubberA;
      static bool       s_bInit = false;
      if (!s_bInit)
      {
        GetMengeGeblubber ().Add (s_GeblubberA);
        s_bInit = true;
      }
      return s_GeblubberA;
    }
    
    CGebluber & GetGebluberB ()
    {
      static CGeblubber s_GeblubberB;
      static bool       s_bInit = false;
      if (!s_bInit)
      {
        GetMengeGeblubber ().Add   (s_GeblubberB );
        s_GeblubberB.SetRelationTo (GetBluberA ()); 
        s_bInit = true;
      }
      return s_GeblubberA;
    }
    

Anmelden zum Antworten