Template nicht rechtzeitig initialisiert


  • Mod

    Warum sollte man das wollen? Die Abhängigkeit von A<float>::PreInitData.data ist hier ja überhaupt erst dadurch sinnvoll, dass wir wollen, dass PreInitData an dieser Stelle bereits (richtig) initialisiert ist. Mithin müsste die Frage eher lauten, wie das Ganze modifiziert werden muss, damit diese Initialisierung sicher rechtzeitig stattgefunden hat.



  • Vielleicht mit einer statischen Methode, und die Variable statisch zur Methode statt zur Klasse machen?

    // Datei A.h
    
    #pragma once
    
    template <class T> class A {
      public :
    
      T data;  
    
      static const A<T>& getPreInitData();
    
      A(T x);
    };
    
    template <class T> const A<T>& A<T>::getPreInitData()
    {
      static const A<T> preInitData(100.0);
      return preInitData;
    }
    
    template <class T> A<T>::A(T x) {
      data= x;
    }
    

    Jetzt müsste beim ersten Aufruf von getPreInitData() doch auf jeden Fall preInitData initalisiert werden oder nicht?
    @OP: was willst du überhaupt damit erreichen? das sieht mir ein wenig nach Singleton-Pattern aus, nur dass du den Ctor und auch die Attribute (!) sämtlich public gemacht hast (was bei Attributen in 99,9% der Fälle schlecht ist, wenns nicht grade um einfache Datenbündel-Structs geht)



  • Vielen Dank für die Antworten!

    Warum läuft denn der Code in A.h in 3) dynamic-initialization?
    Mit dynamisch ist doch zur Laufzeit gemeint? Sorry wenn die
    Frage doof ist 🙄


  • Mod

    Weil A dank des selbst deklarierten Konstruktors kein POD ist.



  • Mhm aber auch wenn ich A.h so ändere...

    template <class T> const A<T> A<T>::PreInitData= 100.0;

    ...d.h. für die initialisierung nicht den selbst
    deklarierten Konstruktor verwende, bekomm ich in
    B.cpp immernoch ne 0.0 statt 100.0.

    Dabei müßte doch jetzt alles auf statischer Ebene ablaufen? 😕



  • Auch wenn Du das Datum jetzt anders initialisierst, ist A immernoch kein POD. Darüberhinaus erzeugen "A a(...)" und "A a = ..." den gleichen Code, sie haben nur etwas andere Anforderungen bezüglich der Semantik des Objekts (expliziter vs. impliziter Konstruktor, Zuweisung muss möglich sein).



  • Gott ist der Code verworren und unübersichtlich, und das mit bloss ein paar Zeilen. Pfui Deibel.
    Ich habe im Übrigen Mist geschrieben denke ich, ist beides dynamische Initialisierung. Hab mich zuerst "verguckt" und geglaubt eins davon wäre ne einfache Variable (eingebauter Typ), aber es geht ja beide male um ein A<T>.

    Und A<T> ist wie camper schon schreibt kein POD und wird dauer auch nicht statisch initialisiert, sondern dynamisch, und zwar indem der Konstruktor aufgerufen wird.

    BTW: ich finde es ziemlich grausig wenn eine Klasse ein statisches Member des eigenen Typs hat. Und WENN man sowas schon machen muss, dann wäre ein besserer Name als "PreInitData" sicher hilfreich.

    Also nochmal konkret: A<float>::PreInitData und B::p sind beides Instanzen von A<float> und werden daher beide dynamisch initialisiert (nach der zero-initialization natürlich). Ob nun aber A<float>::PreInitData oder B::p zuerst drankommt ist purer Zufall, da die Reihenfolge nicht definiert ist.

    Und ich hoffe nicht schonwieder etwas übersehen zu haben.



  • mhm okay danke euch allen 👍 🙂



  • @pumuckl:

    Deine Lösung funktioniert! Danke!
    Aber warum funktioniert das? 😕



  • Gast2008 schrieb:

    Aber warum funktioniert das? 😕

    Weil die statische Variable innerhalb der Funktion auf jeden Fall initialisiert wird, sobald die Funktion das erste Mal aufgerufen wird.
    Ich überlasse das jetzt mal den Profis, festzustellen in welcher der init-phasen das jetzt genau stattfindet, es funktioniert auf jeden Fall so gut wie immer.

    Was nicht funktionieren kann ist natürlich wenn sich zwei Initialisierungsroutinen für statische Funktionsmember gegenseitig aufrufen, etwa folgender Art:

    struct Foo {
      static int get();
    };
    
    struct Bar {
      static int get()
      {
        const static int i = Foo::get();
        return i;
      }
    };
    
    int Foo::get()
    {
      const static int f = Bar::get();
      return f;
    }
    

    Aber kein halbwegs vernünftiger Entwickler würde solche Kreisabhängigkeiten produzieren 😉


Anmelden zum Antworten