globale Variablen in header-Dateien



  • Servus,

    ich habe in meinem neuen Projekt ein paar Singletons, für die ich jeweils globale Pointer anlegen will, um nicht dauernd über ::getInstance() zugreifen zu müssen.

    Daher habe ich versucht, einfach innerhalb der .h-Datei, und zwar unter der class-Definition, einen globalen Pointer zu machen, also etwa so:

    #ifndef _BLABLA_H_
    #define _BLABLA_H_
    
    class Blabla
    {
    // singleton zeugs...
    };
    
    Blabla* bla = Blabla::getInstance();
    
    #endif
    

    Leider funktioniert das nicht. Sobald ich das kompilieren will, sagt mir der Linker, das Symbol wäre schon anderswo definiert. Dabei steht die Deklaration ja innerhalb des #ifndef, also kann es nicht an mehrfachen includes liegen.

    Danach habe ich einfach mal versucht, statt der Pointer-Zeile einfach mal ein int a = 45; reinzuschreiben, aber auch hier tritt exakt der gleiche Fehler auf.

    Weiß jemand, woran das liegt? Wenn ich sowas global in eine .cpp-Datei schreibe, funktioniert es tadellos. Daher dachte ich auch zuerst an mehrfaches includen, aber wie gesagt, es steht korrekt innerhalb des #ifndef. Und zudem ist es sogar so, daß dort, wo angeblich das Symbol bereits definiert wurde, die .h-Datei sowieso nicht includet wird.



  • Hallo

    Warum verwendet du nicht einfach eine freie inline Funktion?

    chrische



  • Hallo

    Include Guards schützen nur vor Mehrfachdefinition in einer Übersetzungseinheit : also etwas was den Compiler betrifft. Da du aber einen Linkerfehler bekommst macht schon deutlich das du ein Problem beim Zusammenspiel mehrerer Übsersetzungseinheiten hast.
    Und zwar genauer taucht nun in jeder Übersetzungseinheit ein eigener Zeiger bla auf und wird jedesmal mit getInstanzce initialisiert.
    Um das zu lösen must du extern verwenden :

    // Header
    extern Blabla* bla;
    
    // Implementation
    Blabla* bla = Blabla::getInstance();
    

    Jetzt gibt es auch wirklich für alle Übersetzungseinheiten nur genau einen Zeiger.
    Aber auch ich würde eine einfache Funktion bevorzugen, was verhindert das doch jemand schreibend auf den Pointer selber zugreift

    bis bald
    akari



  • Hmm ich komm jetzt grad nicht ganz mit, was genau meint ihr denn mit der inline-Funktion?



  • Hallo

    Eine Funktion die im Header des Singletons steht und nichts weiter macht als

    Blabla* bla get()
    {
      return Blabla::getInstance();
    }
    

    Damit hast du einerseits einen einfachen Aufruf, anderseits kann das der Compiler in den meisten Fällen direkt in den Aufruf inlinen, also keine zusätzlichen Funktionsaufruf (zusätzlich zu getInstance)
    Der Vorteil gegenüber der extern-Pointer Variante ist das von außen der interne Singleton-Pointer nicht umgelenkt werden kann.

    bis bald
    akari



  • Hmm aber ob ich nun get() oder getInstance() aufrufe, ist doch dann komplett egal, oder nicht?

    Meine getInstance() sieht folgendermaßen aus:

    static Blabla* getInstance()
    {
        static Blabla* instance;
    
        if (instance == NULL)
            instance = new Blabla;
    
        return instance;
    }
    

    Und genau das würde ja dann nach wie vor passieren, also inkl. dem NULL-Check, wenn ich get() aufrufe. Und daß get() ge-inlined wird, bringt ja dann auch nur, daß der Aufruf eben nicht noch umständlicher wird, aber gewonnen habe ich dadurch doch überhaupt nix?

    Ich glaub da gefällt mir die extern-Lösung besser, funktionieren tut's jedenfalls ausgezeichnet 😉 Vielen Dank!



  • Rock Lobster schrieb:

    Meine getInstance() sieht folgendermaßen aus:

    static Blabla* getInstance()
    {
        static Blabla* instance;
    
        if (instance == NULL)
            instance = new Blabla;
    
        return instance;
    }
    

    Jetzt ändere die mal in

    static Blabla* getInstance()
    {
        static Blabla instance;
        return &instance;
    }
    

    Dann wird sogar korrekt aufgeräumt.

    und dann mach aus dem Zeiger noch ne Referenz und das ganze ist noch bequemer zu verwenden:

    static Blabla & getInstance()
    {
        static Blabla instance;
        return instance;
    }
    

    Musst dann natürlich auch den anderen Kram anpassen:

    // Header
    extern Blabla & bla;
    
    // Implementation
    Blabla & bla = Blabla::getInstance();
    


  • Hmm danke, da sieht man mal wie Java-verseucht ich schon bin 🙄

    Nur das mit dem zweiten Punkt erschließt sich mir nicht so ganz, im Prinzip ist es doch egal, ob ich mit dem Pointer und -> oder direkt mit dem Objekt und . arbeite, oder? Bzw. ist es genau das, was Du damit bezweckst, oder gibt's da noch 'nen anderen Vorteil?


Anmelden zum Antworten