Singleton kuerzer?
-
Falls man von der Klasse mehrere Objekte erstellen will, hat diese nichts mehr mit einer Singleton Klasse zu tun. Man sollte vorher überlegen ob es Sinn ergibt ein Singleton darauszumachen. Eine halbe Singletonklasse es nämich das Sinnfreie daran. Sowieso sieht dein Singleton, meiner Meinung nach, ziemlich merkwürdig aus und wenn du jetzt schon mit dem Gedanken spielst, dass du mehrere Objekte verwenden wirst, lass das Singleton weg. Wenn du nur ein Objekt brauchst, dann erstellst du halt nur eins.
-
Singletons sind sowieso sinnfrei. Ganz speziell in diesem Fall. Aber auch sonst.
-
hustbaer schrieb:
Singletons sind sowieso sinnfrei. Ganz speziell in diesem Fall. Aber auch sonst.
Das ist ebenfalls sinnfrei...
-
Ja, vermutlich.
-
ingobulla schrieb:
2 Gruende:
-
zu wenig Schlaf
-
ich wollte folgendes trennen:
-
den Teil vom Singleton, den jede Klasse RandomNumberGenerator haben wuerde, wenn ich mich irgendwann entscheiden sollte, dass es doch mehr als nur eine Instanz von RandomNumberGenerator geben soll
-
den Teil, der nur vorhanden ist, wenn man RandomNumberGenerator als Singleton verwendet (und nicht, wenn man irgendwann mehrere Instanzen haben sollte)
Gut, Grund 1 ist bekannt als Verursacher merkwürdiger Konstruktionen.
Aber Grund 2 ist irgendwie fragwürdig. Wenn Singleton, dann richtig. Oder halt keins.hustbaer schrieb:
Singletons sind sowieso sinnfrei. Ganz speziell in diesem Fall. Aber auch sonst.
Meinst du wirklich? Warum?
-
-
mad_martin schrieb:
Meinst du wirklich? Warum?
Ich würde Singletons nicht unbedingt als sinnfrei, das Singleton-Pattern aber auf jeden Fall als gefährlich bezeichnen - besonders im Hinblick auf Lazy Initialisation und Multithreading.
Persönlich lasse ich mir Singletons daher, wo nötig, vom Framework bereitstellen (in Java Spring, in C++ pococapsule).
-
Kessi-MC schrieb:
besonders im Hinblick auf Lazy Initialisation und Multithreading.
Erklär mal.
Ich gehe erstmal vom Meyers-Singleton aus.Lazy Initialisation (oder auf englisch lazy initialization) ist doch keine Gefahr, sondern ein kleiner Bonus. Egal, wie spät die Initialisierung stattfindet, es ist immer noch rechtzeitig. Ich sehe da keine Gefahr.
Multithreading ist doch keine Gefahr. Der Compiler schützt die Initialisierung von static-Variablen schon. http://stackoverflow.com/questions/1270927/are-function-static-variables-thread-safe-in-gcc
Kessi-MC schrieb:
Persönlich lasse ich mir Singletons daher, wo nötig, vom Framework bereitstellen (in Java Spring, in C++ pococapsule).
Brilliant.
-
volkard schrieb:
Multithreading ist doch keine Gefahr. Der Compiler schützt die Initialisierung von static-Variablen schon. http://stackoverflow.com/questions/1270927/are-function-static-variables-thread-safe-in-gcc
Das wäre wirklich schön *seufz*.
Bloß trifft es nach dem, was man unter deinem Link findet, nur auf GCC zu. Jemand sagt dort explizit, dass MSVC es nicht so macht. Die Lösung ist also bestenfalls uneinheitlich, was ich nachvollziehbar finde, da der Standard (bisher) Threads ignoriert. Ein ernsthafter Singleton-Bauer muss also wohl davon ausgehen, dass die Initialisierung lokaler statischer Variablen nicht Thread-Save ist.
Trotzdem sollte man das Pattern natürlich nicht pauschal verdammen. Es kann unter Umständen schon nützlich sein.
Stefan.
-
Jemand sagt dort explizit, dass MSVC es nicht so macht.
Das kann ich persönlich bestätigen

Und damit ist (Korrektur: wäre) auch bloss das Thema Initialisierung erledigt. Das Cleanup-Problem löst sich dadurch nicht.
-
hustbaer schrieb:
Und damit ist (Korrektur: wäre) auch bloss das Thema Initialisierung erledigt. Das Cleanup-Problem löst sich dadurch nicht.
Bitte nicht hauen
aber ich nehme das nicht allzu ernst. Klar, wenn man sich theoretisch mit Singletons beschäftigt oder eine allgemeine Klasse schreiben möchte, sollte man sich schon mit Initialisierung und Cleanup auseinandersetzen. Sei es, um Kunden der Klasse über die Einsatz-Bedingungen aufzuklären.Andererseits aber funktionieren konkrete Singletons meiner Erfahrung nach sehr gut. Es gibt oft gar keinen Grund, sich um die (theoretischen) Schwierigkeiten zu kümmern.
Und außerdem: Was wäre die Alternative? Offene globale Variablen sicher nicht. Das Herumreichen von Objekten meist auch nicht. Insgesamt meine ich, dass man die Gefahren des Patterns schon kennen sollte - diese aber andererseits bei konkreten Anwendungsfällen gar nicht ins Gewicht fallen. Und bevor man sich mit den Alternativen einen abbricht, nimmt man halt ein Singleton.
Stefan.
-
Warum ist ein Singleton globalen Funktionen + Namespace überlegen? Warum nicht einfach:
namespace RandomNumberGenerator { unsigned get_counter(); double uniform_01(); }
-
Ben04 schrieb:
Warum ist ein Singleton globalen Funktionen + Namespace überlegen? Warum nicht einfach:
namespace RandomNumberGenerator { unsigned get_counter(); double uniform_01(); }Weil hinter einem Singleton eine Klasse steckt, die Member kapselt. Somit muss nicht irgendwo ein globales Objekt runliegen, wenn du mit mehreren Methoden darauf zugreifen willst.
Z.B....
-
Ben04 schrieb:
Warum ist ein Singleton globalen Funktionen + Namespace überlegen? Warum nicht einfach:
namespace RandomNumberGenerator { unsigned get_counter(); double uniform_01(); }Lokale Zufallszahlengeneratoren können Vorteile haben. Deswegen mag man "class RandomNumberGenerator". Meistens braucht man aber dann doch nur einen globalen und den macht man zum Singleton, damit das Kind keinen so häßlichen Namen hat.
-
Joladrio schrieb:
Ben04 schrieb:
Warum ist ein Singleton globalen Funktionen + Namespace überlegen? Warum nicht einfach:
namespace RandomNumberGenerator { unsigned get_counter(); double uniform_01(); }Weil hinter einem Singleton eine Klasse steckt, die Member kapselt. Somit muss nicht irgendwo ein globales Objekt runliegen, wenn du mit mehreren Methoden darauf zugreifen willst.
Z.B....namespace RandomNumberGenerator { unsigned get_counter(); double uniform_01(); } // ... namespace RandomNumberGenerator { static int my_data = 0; unsigned get_counter(){ ... } }Welche globale Variable?
volkard schrieb:
Ben04 schrieb:
Warum ist ein Singleton globalen Funktionen + Namespace überlegen? Warum nicht einfach:
namespace RandomNumberGenerator { unsigned get_counter(); double uniform_01(); }Lokale Zufallszahlengeneratoren können Vorteile haben. Deswegen mag man "class RandomNumberGenerator". Meistens braucht man aber dann doch nur einen globalen und den macht man zum Singleton, damit das Kind keinen so häßlichen Namen hat.
Du willst also kein Singleton sondern eine globale Instanz deiner Klasse. Lokal instantiieren kann man das Singleton aus dem ersten Post jedenfalls nicht.
-
Ben04 schrieb:
Du willst also kein Singleton sondern eine globale Instanz deiner Klasse.
Im Prinzip schon. Wobei das späte Initialisieren zum Beispiel beim Mersenne Prime Twin Generator auch ganz lecker ist. Ich will aber keinen Zwang, daß es nur eine Instanz geben kann.
Ben04 schrieb:
Lokal instantiieren kann man das Singleton aus dem ersten Post jedenfalls nicht.
Jetzt in ich ein trauriger Programmierbär.
-
Ben04 schrieb:
namespace RandomNumberGenerator { unsigned get_counter(); double uniform_01(); } // ... namespace RandomNumberGenerator { static int my_data = 0; unsigned get_counter(){ ... } }Welche globale Variable?
OK, global ist sie nicht, aber eben nicht gekapselt.
Ich kann von außen RandomNumberGenerator::my_data verändern, ohne dass die Methoden etwas davon mibekommen, und das kann ziemlich Mist erzeugen. Im Falle eines Zufallszahlengenerators z.B. eine nicht reproduzierbare Änderung in der Zahlenfolge.
Nicht nett, dass du das eigentliche Argument, nämlich die Kapselung durch die Klasse, einfach unterschlägst und auf einem falsch verwendeten Begriff rumreitest.
-
Joladrio schrieb:
OK, global ist sie nicht, aber eben nicht gekapselt.
Doch. Sogar besser, da die außen Welt noch nicht mal von ihrer Existenz zu wissen braucht.
Joladrio schrieb:
Ich kann von außen RandomNumberGenerator::my_data verändern
Nein, das geht nicht (außer du packst mehr in die cpp Datei als du solltest). Noch nicht mal mit wildem Casten kommst du an die Variable ran.
-
DStefan schrieb:
Andererseits aber funktionieren konkrete Singletons meiner Erfahrung nach sehr gut. Es gibt oft gar keinen Grund, sich um die (theoretischen) Schwierigkeiten zu kümmern.
Mach mal Logging mit einem Singleton-Logger.
Und dann mach bitte Log-Ausgaben im Destruktor von anderen Singleton-Klassen.
Oder im Destruktor von anderen Klassen, die irgendwo auch mal auf File-Scope instanziert werden.p.S.:
Die "beste" Möglichkeit sich um die Zerstörungs-Problematik zu kümmern, ist IMO oft, die Singletons einfach garnicht zu zerstören. Einfach mit "new" anfordern, und nie ein "delete" drauf machen.Bei Dingen wie einem Log-Writer kann das natürlich zu anderen Problemen führen. z.B. wenn man buffered Writes ins Logfile macht. Dann können schnell mal die letzten paar Zeilen fehlen. Kann man aber z.B. dadurch vermeiden, dass man (über ein Objekt einer Hilfsklasse) während der Statischen Deinitialisierungsphase das Buffering ausschaltet.
-
Was Zufallszahlen-Generatoren angeht: niemals global/Singleton.
Warum? Weil man sonst ein Problem mit Threads bekommt. Und Zugriffe auf einen RNG zu synchronisieren ist ... nunja ... ziemlich grober Overhead.
-
hustbaer schrieb:
DStefan schrieb:
Andererseits aber funktionieren konkrete Singletons meiner Erfahrung nach sehr gut. Es gibt oft gar keinen Grund, sich um die (theoretischen) Schwierigkeiten zu kümmern.
Mach mal Logging mit einem Singleton-Logger.
Und dann mach bitte Log-Ausgaben im Destruktor von anderen Singleton-Klassen.
Oder im Destruktor von anderen Klassen, die irgendwo auch mal auf File-Scope instanziert werden.Ja klar, ein Logger ist natürlich das Killer-Beispiel. Da rennst du bei mir offene Türen ein

Ich wollte auch nicht sagen, dass das Konzept Singleton trivial sei, sondern bloß, dass konkrete Singletons oft ganz ohne Fisematenten bestens funktionieren.
Sozusagen der pragmatische Ansatz.
hustbaer schrieb:
p.S.:
Die "beste" Möglichkeit sich um die Zerstörungs-Problematik zu kümmern, ist IMO oft, die Singletons einfach garnicht zu zerstören. Einfach mit "new" anfordern, und nie ein "delete" drauf machen.Genauso mache ich es im Zweifelsfall auch. Und verlasse mich darauf, dass mein OS den Speicher am Programm-Ende ohnehin frei gibt.
Stefan.