Singleton -> Verwirrung



  • Hallo,

    folgende Codestücke sind irgendwie zu hoch für mich:

    main.cpp

    FileSystem::inst().foobar()
    

    filesystem.h

    class FileSystem : public Singleton<FileSystem>
    {
    	friend class Singleton<FileSystem>;
    
    public:
    	void foobar();
    }
    

    singleton.h

    template<typename T> class Singleton
    {
    protected:
    	Singleton()
    	{
    	}
    
    	Singleton(const Singleton<T>& rhs)
    	{
    	}
    
    	~Singleton()
    	{
    	}
    
    	Singleton<T>& operator = (const Singleton<T>& rhs)
    	{
    	}
    
    public:
    	static T& inst()
    	{
    		static T theOneAndOnly;
    		return theOneAndOnly;
    	}
    };
    

    Meine Frage ist jetzt folgende: Der Aufruf FileSystem::inst() in der main.cpp gibt mir ja die statische Instanz aus der singleton-Klasse zurück, ist also vom Typ FileSystem. Warum krieg ich denn jetzt eine Fehlermeldung, wenn ich die friend-Deklaration aus der filesystem.h rausnehme? Ich rufe doch jetzt das .foobar() nicht aus der singleton-Klasse auf 😕

    Und wozu macht man sich überhaupt diesen Aufwand mit singletons? Klar, es soll nur eine Instanz einer Klasse geben, aber der Programmierer müsste doch wissen, wo er sich welche Instanz erstellt und wenn er nur eine braucht, erstellt er sich wahrscheinlich auch nur eine. Wozu also diese Sicherheit?



  • Der Konstruktor deines Singleton ist durch Vorgabe des Klassentemplates protected. Die Basisklasse muss aber eine Instanz von FileSystem erzeugen können und braucht deshalb Zugriff auf den protected-Konstruktor.

    Würdest du inst() im Klassemtemplate rauslassen, oder besser als virtual deklarieren, könntest du die Instanz in der Implementation von FileSystem erzeugen und auf die friend-Deklaration verzichten. Ich denke, so wie es hier steht, ist es aber die eleganteste Lösung.

    Warum betreibt man den Aufwand: Sicherheit sollte eigentlich als Argument schon reichen, aber angenommen du musst *irgendwo* aus deiner Anwendung heraus auf das Singleton zugreifen. Wie machst du das?

    Die dumme Lösung: Das Singleton auf den Heap packen und den Zeiger darauf global verfügbar machen. Das Objekt kann plötzlich futsch sein, oder irgendjemand erzeugt dann doch mal eine zweite Instanz, aus Unwissenheit.

    Die gute Lösung: Das Singleton-Muster.

    Keine Gewähr auf Richtigkeit, ich bin heute auch schon müde...



  • stellt sich die Frage warum Filesystem ein Singleton sein muss? Darf es immer nur ein Filesystem geben?



  • die andere Frage: warum macht man die member von filesystem nicht statisch? da braucht man nicht einmal ein sigelton?



  • okay nochmal ganz langsam zum Mitdenken 🙂

    Spekulant schrieb:

    Der Konstruktor deines Singleton ist durch Vorgabe des Klassentemplates protected. Die Basisklasse muss aber eine Instanz von FileSystem erzeugen können und braucht deshalb Zugriff auf den protected-Konstruktor.

    Die Basisklasse ist singleton. Da FileSystem von singleton erbt, müsste der protected-Konstruktor zu einem privaten Konstruktor in FileSystem werden. In dem Moment, wo ich also FileSystem() aufrufe, braucht doch keine Klasse Zugriff auf eine andere oder sehe ich das falsch?

    Spekulant schrieb:

    Würdest du inst() im Klassemtemplate rauslassen, oder besser als virtual deklarieren, könntest du die Instanz in der Implementation von FileSystem erzeugen und auf die friend-Deklaration verzichten. Ich denke, so wie es hier steht, ist es aber die eleganteste Lösung.

    Dazu kenne ich mich jetzt zu wenig mit virtual aus. Ich weiß nur, dass das dann Typenchecks während der Laufzeit ausführt, aber so ganz fassen, kann ich die Bedeutung davon gerade nicht 😃

    Ansonsten aber schonmal vielen Dank, ist um einiges klarer geworden!



  • Wenn du nur ein paar funktionen wie mkdir haben willst, auf die du überall zugreifen kannst, dann mach die in einen namespace und kein singleton



  • Nochmal eine andere Frage. Gegeben ist folgender Code:

    FileSystem::inst().foobar();
    FileSystem::inst().foobar();
    

    Warum funktioniert dieser Code? Ich dachte es darf nur eine Instanz von FileSystem geben. Über statische Variablen weiß ich, dass sie erst bei der Definition initialisiert werden, also in dem Fall doch nie, weil immer nur die Adresse von T aus der inst() Methode in singleton zurückgegeben wird 😕



  • static T& inst()
        {
            static T theOneAndOnly; // hier wird theOneAndOnly initialisiert
            return theOneAndOnly; // und hier per Referenz zurückgegeben
        }
    

    Dank static wird theOneAndOnly nicht reinitialisiert und auch nicht zerstört, wenn der Scope von inst() verlassen wird.



  • banshee schrieb:

    Über statische Variablen weiß ich, dass sie erst bei der Definition initialisiert werden, also in dem Fall doch nie, weil immer nur die Adresse von T aus der inst() Methode in singleton zurückgegeben wird 😕

    Es wird nicht die Adresse, sondern eine Referenz auf T zurückgegeben.

    Es findet auch eine Definition statt, nämlich mit

    static T theOneAndOnly;
    


  • Danke für die Zusammenfassung meines Posts 😉



  • mad_martin schrieb:

    Danke für die Zusammenfassung meines Posts 😉

    Sag mir bitte, wo du etwas von einer Definition erwähnt hast. Du hast auch nicht ausdrücklich gesagt, dass keine Adresse zurückgegeben wird (was aber wichtig wäre, um Missverständnisse des Fragestellers zu vermeiden).

    Verzichte bitte in Zukunft auf solche Kommentare, wenn sie nicht berechtigt sind.



  • Ok, die Definition habe ich nicht ausdrücklich erwähnt.
    Und sieh dir mal den zweiten Kommentar des Codes an...

    Kein Grund, hier direkt so abzugehen!



  • mad_martin schrieb:

    Und sieh dir mal den zweiten Kommentar des Codes an...

    Und lies mal den zweiten Satz in meinem oberen Post...

    mad_martin schrieb:

    Kein Grund, hier direkt so abzugehen!

    Ich sagte nur, du solltest dir solche Bemerkungen in Zukunft verkneifen. Es nervt einfach, wenn man sich Mühe für eine Antwort gibt und dann muss man sich von anderen noch dumme und völlig unberechtigte Kommentare anhören.


Anmelden zum Antworten