Singletons



  • jooker schrieb:

    Das ist ein kleines Beispiel aus dem Buch.

    Warum schrieb der Autor in den ersten zeilen:
    #ifndef TSINGLETON
    #define TSINGLETON

    und zum schluss:
    #endif

    Die Dinger nennen sich Include Guards

    Die Implementierung is allerdings etwas seltsam. Der Konstruktor (& Copy c'tor) sind öffentlich. Der Destruktor könnte auch protected gemacht werden, dann kann man sich "virtuellen" Overhead sparen.
    Get sollte lieber eine Referenz zurückgeben und könnte z.B. auch als Mayers-Singleton implementiert werden (das spart dir diese if-Abfrage). Bei Del ist die if-Anweisung unnötig. Uswusf...



  • Also ich nutze imer diese Variante, die finde ich Persönlich besser.

    class Singleton
    {
    private:
        CTor;
        Copy-CTor;
        Operator=;
    private:
        DTor;
        static Singleton& getInstance()
        {
            static Singleton single;
            return single;
        };
    };
    

    Wobei das dann auch kein Template ist sondern in der Klasse direkt integriert.



  • Also haben die Singeltons im Grunde nur ein vorteil:
    Sie schaffen Ordnung und übersichtlichkeit da man seperat eine Singleton klasse in einer hpp datei speichern kann von wo aus sich einfach eine Instanz erzeugen lässt welche an die cpp Datei übergeben werden kann.

    ich hoffe ich hab es jetzt abschließend richtig erklärt,
    wenn ich was vergessen hab zu erwähnen,sagt es mir bitte.



  • Das is schonmal Nah dran aber immernoch daneben. Durch die Singletons braucht man garkeine globale Variable mehr, man erstellt sie als Normale Klasse, zB ein TexturManager, und jeder der was daran machen will kann sich über getInstance eine Referenz auf die Instanz holen, somit braucht man keine globale Variable mehr.



  • jooker schrieb:

    Also haben die Singeltons im Grunde nur ein vorteil:

    Du meinst einen.

    ich hoffe ich hab es jetzt abschließend richtig erklärt

    Nein. Von Singletons kann es nur eine einzige Instanz geben, wie es der Name auch schon nahelegt. Das ist sein Zweck.



  • Xebov schrieb:

    Durch die Singletons braucht man garkeine globale Variable mehr

    "Global" im formalen Sinne von C++ vielleicht nicht.

    Wenn man unter "global" jedoch das Konzept versteht, Zugriff von überall her direkt zu ermöglichen, gehören Singletons sehr wohl dazu (wie auch schon erwähnt wurde).



  • Xebov schrieb:

    [...] somit braucht man keine globale Variable mehr.

    Was ist mit globalen Referenzen? Sowas lässt sich nicht mit einem Singleton realisieren.



  • Nexus schrieb:

    Wenn man unter "global" jedoch das Konzept versteht, Zugriff von überall her direkt zu ermöglichen, gehören Singletons sehr wohl dazu (wie auch schon erwähnt wurde).

    OK, das is dann wieder sone Auslegungssache wie mans versteht.

    David_pb schrieb:

    Was ist mit globalen Referenzen? Sowas lässt sich nicht mit einem Singleton realisieren.

    Ich evrstehe nicht ganz worauf du hinaus willst? Ich bezog mich darauf das ich mit der Singleton keine globale Variable mehr brauche da der Zugriff von überall ja möglich ist. Das man Singletons nicht für jede Kleinigkeit einsetzt setze ich jetzt einfach mal voraus.



  • David_pb schrieb:

    Was ist mit globalen Referenzen? Sowas lässt sich nicht mit einem Singleton realisieren.

    Was meinst du mit globaler Referenz?

    So etwa ?

    SingletonType& a = SingletonType::getInstance();
    

    Is zwar nicht möglich,
    aber getInstance sollte ja eine Referenz zurückgegeben ( und keinen Zeiger),
    daher hat sich das in meinen Augen schon eliminiert.

    Oder hab ich dich falsch verstanden ?



  • Xebov schrieb:

    Also ich nutze imer diese Variante, die finde ich Persönlich besser.

    class Singleton
    {
    private:
        CTor;
        Copy-CTor;
        Operator=;
    private:
        DTor;
        static Singleton& getInstance()
        {
            static Singleton single;
            return single;
        };
    };
    

    Wobei das dann auch kein Template ist sondern in der Klasse direkt integriert.

    find ich zwar eigtl auch toll, aber dummerweise kann man die zerstörungs-reihenfolge eben nicht festlegen : <

    bb



  • Xebov schrieb:

    Ich evrstehe nicht ganz worauf du hinaus willst? Ich bezog mich darauf das ich mit der Singleton keine globale Variable mehr brauche da der Zugriff von überall ja möglich ist. Das man Singletons nicht für jede Kleinigkeit einsetzt setze ich jetzt einfach mal v******.

    Angenommen du benötigst eine globale Zugriffsstelle für irgendwas, wobei du aber die Implementierung von irgendwas austauschbar machen willst. Dann würde sich z.B. eine globale Referenz (also im Endeffekt auch eine Art globale Variable) anbieten. Wie würdest du das mit einem Singleton realisieren?



  • Die globale Referenz hat aber nur den Vorteil, daß Du
    cout.foo();
    schreiben kannt.

    Wenn ich bereit bin,
    cout().foo();
    zu schreiben, brauche ich keine globalen Referenzen mehr.



  • Oder wenn man es mit dem Gewissen vereinbaren kann: Makros. Bei Singletons finde ich die legitim, denn jedes Mal MySingleton.GetInstance().DoSomething(); zu schreiben ist mühsam und bringt nicht wirklich was. Wenns nur ab und zu vorkommt, kann mans schon so machen.

    Bei globalen Referenzen muss man je nach Ziel auch aufpassen, dass es bereits existiert, wenn die Referenz erstellt wird. Oder dass die Referenz bereits initialisiert ist, wenn man auf sie zugreift.



  • Es geht mir nicht um eine Kurzschreibweise. Folgendes Beispiel:

    class Base
    {
    public:
    	virtual void foo() = 0;
    };
    
    class Derived1 : public Base
    {
    public:
    	virtual void foo()
    	{
    	}
    };
    
    class Derived2 : public Base
    {
    public:
    	virtual void foo()
    	{
    	}
    };
    
    extern Base& g_something;
    
    // irgendwo modulglobal, oder sonstwas
    Derived2 bla;
    Base& g_something = bla;
    
    // oder
    Derived1 bla;
    Base& g_something = bla;
    

    Nexus schrieb:

    Bei globalen Referenzen muss man je nach Ziel auch aufpassen, dass es bereits existiert, wenn die Referenz erstellt wird. Oder dass die Referenz bereits initialisiert ist, wenn man auf sie zugreift.

    Die Referenz muss doch initialisiert sein, ansonsten streikt der Compiler bereits.



  • David_pb schrieb:

    Die Referenz muss doch initialisiert sein, ansonsten streikt der Compiler bereits.

    Nicht, wenn eine Deklaration der Referenz vorliegt.

    // Header
    extern MyClass& Reference;
    
    // Implementierungsdatei
    MyClass& Reference = ...;
    

    Da die Initialisierungsreihenfolge globaler Variablen in unterschiedlichen Übersetzungseinheiten nicht festgelegt ist, kann es sein, dass ein Zugriff auf Reference erfolgt, bevor die Referenz initialisiert wurde.

    Aber solche Fälle scheinen mir generell eher realitätsfern. Oder setzt du häufig globale Referenzen ein?



  • Nexus schrieb:

    Aber solche Fälle scheinen mir generell eher realitätsfern. Oder setzt du häufig globale Referenzen ein?

    Mag sein, das solche Fälle selten sind. Aber den Fall gibt es trotzdem und Singletons sind eben kein kompletter Ersatz für globale Variablen, selbst wenn es einige Parallelen gibt.



  • David_pb schrieb:

    Mag sein, das solche Fälle selten sind. Aber den Fall gibt es trotzdem und Singletons sind eben kein kompletter Ersatz für globale Variablen, selbst wenn es einige Parallelen gibt.

    Hä? Versteh ich nicht.
    Warum brauchst Du globale Referenzen? Warum kann der Benutzer nicht g_something() statt g_something schreiben? Willst Du für verschiedene Übersetzungseinheiten andere Bedeutungen hinter der Referenz haben? Das geht eigentlich auch mit g_something() statt g_something. Oder warum sonst?



  • Nein, ich will aber z.B. Vererbungspolymorphie verwenden können und die Implementierung die referenziert wird beim Initialisieren beliebig wählen. Falls der Fall mal real auftreten sollte wüsste ich spontan nicht wie das per Singleton realisierbar wäre, möglich das es ja irgendwie funktioniert?!



  • David_pb schrieb:

    Nein, ich will aber z.B. Vererbungspolymorphie verwenden können und die Implementierung die referenziert wird beim Initialisieren beliebig wählen. Falls der Fall mal real auftreten sollte wüsste ich spontan nicht wie das per Singleton realisierbar wäre, möglich das es ja irgendwie funktioniert?!

    Vererbungspolymorphie kann die Funktion auch.
    Und beliebige Wahl hast Du mit

    namespace {
       Base& g_something(){
          return Derived1::getInstance();
       }
    }
    


  • unskilled schrieb:

    find ich zwar eigtl auch toll, aber dummerweise kann man die zerstörungs-reihenfolge eben nicht festlegen : <

    bb

    Das problem hab ich bei mir mit ner ShutDown Methode gelöst. Ich rufe am beginn von Main einmal getInstance und dann init auf um alles Ordnungsgemäß zu Initalisieren und am ende von Main ShutDown, damit ist die Instanz zwar nicht weg, aber die Arbeit ist erledigt, also Speicher freigegeben usw. Man muß dann nur aufpassen das danach nicht irgendwelche anderen elemente was wollen, da ist dann beim Herunterfahren etwas vorrausplanung gefragt.


Anmelden zum Antworten