Singletons



  • Das gibt dem ganzen auch nicht mehr Sinn. Dein Standarddrucker Beispiel zeigt doch, dass du es nicht verstanden hast. Warum soll der ein Singleton sein? Ganz sicher nicht dazu, dass er ewig im Speicher bleibt. Je nach dem was man vor hat könnte das Ding wo man den Standarddrucker bekommt ein Singleton sein. Wenn einer den Standarddrucker ändert, während er verwendet wird, was passiert dann? Programmcrash?



  • Hast zwar deine Antwort inzwischen erweitert, aber meine passt immer noch so.



  • Danke,
    so langsam verstehe ich das.

    Aber Das thema singelton ist dann ja anscheinend wie Nanyuki schon mit der zeile:
    "Singletons "gibt" es nicht, das ist einfach ein abstraktes Konzept und nicht etwa Teil der Sprache." sagte eher unwichtig und kann vernachlässigt werden oder?



  • Vernachlässigen würde ich es nicht, gibt gute Einsatzgebiete und man solte es zumindest kennen, schon allein deshalbw eil einem so eine Kosntruktion durchaus mal über den Weg laufen kann.



  • #ifndef TSINGLETON
    #define TSINGLETON

    template <class T>
    class TSingleton
    {
    protected:

    // Membervariablen
    static T *m_pSingleton; // Statisches Objekt

    public:

    // Memberfunktionen

    // Destruktor
    //
    virtual ~TSingleton ()
    {
    }

    // Get
    //
    // Aufgabe: Wenn nötig, statisches Objekt erzeugen und
    // Zeiger darauf zurückgeben
    //
    inline static T* Get ()
    {
    // Existiert schon eine Instanz?
    if (!m_pSingleton)
    m_pSingleton = new T; // Nein, dann neue Instanz erzeugen

    // Zeiger auf die Instanz zurückgeben
    return (m_pSingleton);

    } // Get

    // Statisches Objekt freigeben
    //
    static void Del ()
    {
    // Gab es eine Instanz?
    if (m_pSingleton)
    {
    delete (m_pSingleton); // Ja, dann freigeben
    m_pSingleton = NULL; // und Zeiger auf NULL setzen
    }

    } // Del

    };

    // Die statische Variable erzeugen
    //
    template <class T>
    T* TSingleton<T>::m_pSingleton = 0;

    #endif

    Das ist ein kleines Beispiel aus dem Buch.

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

    und zum schluss:
    #endif

    Vielleicht könnte jemand sich nochmal auf das beispiel beziehn,
    wäre euch sehr verbunden,mit beispielen lernt man es besser 😉



  • 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?


Anmelden zum Antworten