Alternative für globale Variablen



  • Du kannst von einer Klasse nichts ableiten, wenn kein Konstruktor als public verfügbar ist.. Wenn du das so mit dieser Vererbung machen willst, dann würde ich eher (wiedermal) das Meyers Singleton empfehlen:
    http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton-Pattern-Part-I/4/



  • Ich habe mich nun doch dazu entschieden, eine separate Singleton-Klasse namens Settings zu erstellen, was auch soweit ganz gut funktioniert. Da ich die Variablen vorher gerne initialisieren möchte, habe ich mich dazu entschlossen, das direkt im Konstruktor zu machen. Das sollte eigentlich kein Problem darstellen, da ja nur maximal ein Objekt der Klasse erstellt werden kann. Ich weiß, dass mein Code (noch) nicht thread safe ist, aber im Allgemeinen sollte es doch mit der Initialisierung der Variablen im Konstruktor keine Probleme geben, oder?

    Hier nochmal der Code:

    class Settings
    {
    private:
    	//Ein Pointer zum Speichern der Instanz
    	static Settings* instance;
        //Konstruktor private, damit man sich keine Instanzen holen kann.
    	Settings()
    	{
    		isettingvalue = 12;
    	}
        //Den Kopierkonstruktor schützen um zu vermeiden, dass das Objekt unbeabsichtigt kopiert wird.
    	Settings(const Settings& cc){}
    	~Settings(){}
    public:
    	static Settings* getInstance();
        static void Destroy();
    	void LoadSettings(std::string FileName);
    
    	bool bsetting;
    	int isettingvalue;
    };
    Settings* Settings::instance = NULL;
    
    Settings* Settings::getInstance()
    {
    	if( !instance )
          instance = new Settings();
        return instance;
    }
    
    void Settings::Destroy()
    {
        if (instance)
    	{
          delete instance;
          instance = NULL;
        }
    }
    
    void Settings::LoadSettings(std::string FileName)
    {
    	//Code zum Laden der Settings
    	// -------------------------
    	bsetting = true;
    	isettingvalue = 5;
    }
    
    int main()
    {
    	Settings *settings = Settings::getInstance();
    	std::cout << "settingvalue before LoadSettings = " << settings->isettingvalue << std::endl; // Output 12
    	settings->LoadSettings("testfile.ini");
    
    	std::cout << "settingvalue = " << settings->isettingvalue << std::endl; // Output 5
    	settings->isettingvalue = 2;
    	std::cout << "settingvalue = " << settings->isettingvalue; //Output: 2
    	std::cin.get();
    
        Settings::Destroy();
    
    	return 0;
    }
    


  • Und was spricht gegen das Meyers Singleton? - Imo braucht man für ein Singleton das rumhantieren mit dem dynamischen Speicher lediglich, wenn man ein etwas spezielleres Singleton machen will, wie z.B ein Phönix Singleton. Aber ansonsten reicht das von Meyers vorgeschlagene.

    Ich finde einfach das hier unnötig und "gefährlich".

    Settings::Destroy();
    


  • Was ist wenn man das Löschen, so wie hier beschrieben:http://www.oop-trainer.de/Themen/Singleton.html, mit einer guard-Klasse macht?



  • Klar kann man. Ich habe das "gefährlich" mit Absicht in Anführungszeichen geschrieben, weil es viele mögliche Implementierungen von Singletons gibt. Oftmals reicht aber Meyers völlig. Und ich bevorzuge eine einfache Lösung, wenn sie passt einer komplizierteren.

    Ich sehe den wirklichen Unterschied dieses Guards nicht wirklich zu Meyers. Läuft ja auf das gleiche hinaus. Wenn allerdings der Guard noch zusätzliche Funkitionalität, wie z.B eine manuelle Zerstörung anbietet, dann ist das etwas völlig anderes. Aber, wie gesagt braucht man das ja eher selten und das Meyers Singleton reicht völlig.



  • Oft ist es ideal wenn man Singletons garnicht zerstört.



  • hustbaer schrieb:

    Oft ist es ideal wenn man Singletons garnicht zerstört.

    Noch öfters ist es ideal, wenn man Singletons garnicht benutzt.



  • hustbaer schrieb:

    Oft ist es ideal wenn man Singletons garnicht zerstört.

    Wenn nur eines vorhanden ist, dann ist es imo weniger tragisch. Dann zerstört es sich einfach als letztes. Sobald man aber Krieg der Singletons bestreiten will, dann wirds problematisch, wer sich selbst zerstört und wer auf den Leichen rumtrampelt.. 🙂



  • AntiPatternInc schrieb:

    Noch öfters ist es ideal, wenn man Singletons garnicht benutzt.

    Vor allem nicht als Alternative zu globalen Variablen. 🙂



  • SinglePattern dürfte man Abstand das überbenutzteste Pattern überhaupt sein und es ist nahezu nie angebracht.
    Ich finde mittlerweile sogar globale Variablen besser als Singletons.



  • Braunstein schrieb:

    Was ist wenn man das Löschen, so wie hier beschrieben:http://www.oop-trainer.de/Themen/Singleton.html, mit einer guard-Klasse macht?

    Dann hat man den Fall nicht zuende gedacht.
    Warum hat der Wächter nur das Löschen und nicht auch noch das Erzeugen?
    In Listing5 fällt die Asymmetrie stark auf.
    Hauen wir das Erzeugen doch mal auch in den Wächter-Konstruktor und beobachten, was geschieht.
    Es erinnert an was bekanntes. Moment, gleich kommts.
    Den instanz-Zeiger und exemplar() auch in den Wächter rein!
    Ja, wir habens raus. Es ist ein Meyers-Singleton, der ein gepimpltes Monster-Objekt hält.



  • Wie gesagt. Den Grund so etwas in diese Richtung zu machen, wäre für mich so etwas:

    class Singleton
    {
       public:
         static Singleton* exemplar();
    
       private:
         static Singleton *instanz;
         Singleton() {}
         Singleton( const Singleton& );
    
         ~Singleton() {}
    
         class Waechter {
             public: ~Waechter() {
               if( Singleton::instanz != 0 )
                 delete Singleton::instanz;
             }
    
             void destroy()
             {
               if ( !Singleton::instanz )
               {
                 delete Singleton::instanz;
                 Singleton::instanz = 0;
               }   
             }
         };
         friend class Waechter;
    };
    

    Somit könnte man das Singleton selbst zerstören, wenn das irgendwie notwenig ist, und wenn man es verigsst wird es automatisch gemacht.



  • auchmalanmerker. schrieb:

    Ich finde mittlerweile sogar globale Variablen besser als Singletons.

    Und ich find Vanilleeis ganz Klasse.
    Mal ehrlich: hier sollte es weniger darum gehen was man an persönlichen Präferenzen für und gegen ein bestimmtes Pattern hat, sondern vielmehr darum, welche Vor- und Nachteile das Pattern in der gegebenen Situation gegenüber den Alternativen hat. Deswegen sollte zu jedem "ich finde" auch ein "weil" geliefert werden. Und zwar nicht "weil Vanilleeis einfach lecker ist".



  • Irgendwie versteh ich die Problematik nicht, die es beim Erzeugen/Zerstören geben soll.

    Wenn ich das wie im Meyer Singleton mache (also eine Referenz auf eine statische lokale Variable liefere), wo ist dann das Problem?
    Erzeugung: Nur wenn man die statische Funktion aufruft, wird das Objekt erzeugt. Passt.
    Zerstörung: Ok da bin ich etwas überfragt. Finde eine statische lokale Variable eh irgendwie magisch. Wann wird diese Variable denn wieder zerstört? Und was genau ist jetzt dieses Zerstör-Problem? Kann da vielleicht jemand bitte ein kleines Beispiel bringen?



  • Statische Variablen werden nach dem Ende der main zerstört.

    Das Problem ist die Reihenfolge, in der zerstört wird, wenn du 2 statische Variablen hast. Was passiert z.B, wenn die einte zerstört wird und die andere bei seiner eigenen Zerstörung auf die bereits zerstört zugreift?



  • Seh da noch immer nicht das Problem. Dann greif ich einfach in den Destruktoren der Singletons auf kein anderes Singleton zu. Dann is doch alles sicher? 😕


  • Administrator

    marti schrieb:

    Seh da noch immer nicht das Problem. Dann greif ich einfach in den Destruktoren der Singletons auf kein anderes Singleton zu. Dann is doch alles sicher? 😕

    Sofern das möglich ist, was aber nicht immer geht. Ich würde das Problem als sehr selten bezeichnen, aber es kommt tatsächlich manchmal vor.
    Deshalb hatte drakon auch gesagt, dass in den meisten Fällen das Meyers Singleton absolut ausreicht.

    Grüssli



  • marti schrieb:

    Seh da noch immer nicht das Problem. Dann greif ich einfach in den Destruktoren der Singletons auf kein anderes Singleton zu. Dann is doch alles sicher? 😕

    Jup. Nur kann man sich da manchmal nicht sicher sein, zum Beispiel hast Du irgendwann Sorgen mit dem Drucker und machst zur Sicherheit mal rein, daß die Druckerdestruktion geloggt wird. Hast aber vergessen, daß nicht nur der Drucker ein Singleton ist, sondern das LOG-Makro innendrin auch einen Singleton verwendet. Schade.
    Aber will man ALLES bedenken im Umgang mit Singletons, hat man irgendwie einen gewissen Spaßverlust.



  • Ok, verstehe. Gibt es sonst noch Fallstricke bei Singletons? Vielleicht Probleme bei Multithreading?



  • Dravere schrieb:

    marti schrieb:

    Seh da noch immer nicht das Problem. Dann greif ich einfach in den Destruktoren der Singletons auf kein anderes Singleton zu. Dann is doch alles sicher? 😕

    Sofern das möglich ist, was aber nicht immer geht. Ich würde das Problem als sehr selten bezeichnen, aber es kommt tatsächlich manchmal vor.
    Deshalb hatte drakon auch gesagt, dass in den meisten Fällen das Meyers Singleton absolut ausreicht.

    Grüssli

    Und wenn der Fehler auftaucht, dann sucht man bestimmt nicht da.. Respektive man debugg sich zu tode bis man auf die Idee kommt den Debugger doch einmal bis ganz ans Ende laufen zu lassen.. 😉

    Aber will man ALLES bedenken im Umgang mit Singletons, hat man irgendwie einen gewissen Spaßverlust.

    No risk, no fun! Code-Cowboys ftw, Programmierer sind auch coole Leute mit Hut und Sonnenbrille. :p *SCNR*


Anmelden zum Antworten