Seite 2 von 6

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 16:34
von dot
Krishty hat geschrieben:Ich ganz persönlich hatte auch noch nie so viele unterschiedliche Logs, dass ich mehr als eine globale Variable bzw. Funktion gebraucht hätte.
Gut, dann ist aber eine globale Variable ausreichend, ein Singleton wäre imo falsch. Der einzige wirkliche Anwendungsfall der mir bisher je untergekommen ist wo ein Singleton evtl. sinnvoll sein könnte ist ein Scheduler in einem Betriebssystem. Bei dem ist es evtl. wirklich eine wesentliche Eigenschaft des Typs dass nur genau eine Instanz existieren darf. Aber selbst da wär ich persönlich sehr skeptisch und würd vermutlich eher kein Singleton verwenden.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 16:41
von Krishty
dot hat geschrieben:Gut, dann ist aber eine globale Variable ausreichend, ein Singleton wäre imo einfach nur falsch.
Die Sache hat aber auch ein Haken: Und das ist C++’ völlig bescheuerte undefinierte statische Initialisierungsreihenfolge. Du kannst darum keine anderen globalen Variablen mehr bei ihrer Initialisierung was loggen lassen – in eine Funktion verpackt hingegen hat man einen eindeutigen Initialisierungszeitpunkt (den Augenblick, in dem es zuerst gebraucht wird).

Ob man dann ein Singleton hat oder nicht hängt dann nurnoch davon ab, ob diese Funktion innerhalb oder außerhalb der Klasse liegt. Für mich eine Formfrage. Darum ist das Singleton auch meines Ermessens nach nicht pauschal falsch.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 16:43
von dot
Krishty hat geschrieben:Die Sache hat aber auch ein Haken: Und das ist C++’ völlig bescheuerte undefinierte statische Initialisierungsreihenfolge. Du kannst darum keine anderen globalen Variablen mehr bei ihrer Initialisierung was loggen lassen – in eine Funktion verpackt hingegen hat man einen eindeutigen Initialisierungszeitpunkt (den Augenblick, in dem es zuerst gebraucht wird).
Ok, das ist zugegeben ein Argument. Allerdings hat man dieses Problem mit Dependency Injection schon rein prinzipell nicht da der Fall dort systematisch bedingt nie eintreten kann. Und daher würde ich letzeres als die definitiv bessere Lösung ansehen.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 16:58
von Krishty
dot hat geschrieben:Allerdings hat man dieses Problem mit Dependency Injection schon rein prinzipell nicht da der Fall dort systematisch bedingt nie eintreten kann.
Wo wir gerade bei Objektorientierungsgrundsätzen sind: Ich für meinen Teil überlege schon lange, ob ich Logging überhaupt objektorientiert handhaben soll und nicht etwa funktional – ich empfinde den Logger mehr und mehr als Gespenst von etwas völlig Funktionalem, was ich nur extrem verkompliziere. Wenn tatsächlich irgendwer loggt, ist das imo eine Handlung meines kompletten Prozesses, also … riecht das nach globaler Funktion.

Zurückgehalten werde ich nur von der Leistung und der Überschaubarkeit der Syntax (log << blubb << "foo"; ist halt eleganter und schneller als log(toString("blubb") + "foo")).

Einfach mal neben die Tüte gekotzt.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 17:04
von CodingCat
Ja, bzgl. globalem Zugriff habe ich Krishty nichts mehr hinzuzufügen. Um nochmal auf das Singleton zurückzukommen, hier hatten wir uns ja schon auf Seite 2 geeinigt, dass ich Singleton im Eingangspost zum Thema Logging zu sehr mit globalem Zugriff vermengt hatte. Die Ursache hierfür, das C++-Singleton-typische Muster der lokal definierten statischen Variable, hat Krishty eben auch schon genannt. Tatsächlich nutze ich zum Logging sogar eine statische Instanz, die lokal in einer freien Funktion definiert ist, ohne dass die Anzahl der konstruierbaren Instanzen prinzipiell beschränkt ist.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 17:11
von dot
Ja, das ist eine gute Frage. Logging ist so eine Sache wo ich auch noch keine wirklich zufriedenstellende Lösung gefunden hab. Ein Log ist sicherlich einer der extrem seltenen Fälle wo man wirklich für ein Singleton oder eine globale Variable argumentieren kann (das wohl beste Argument hast du ja oben gebracht) und ich will ja nicht Cat's Lösung runtermachen oder so. Ich find nur Singleton rein prinzipiell so hässlich dass ich in dem Kontext gern immer ein wenig übertreib, ich persönlich würds, was auch immer passiert, einfach nie tun ;)
Für sehr einfache Dinge verwend ich evtl. einfach einen globalen std::ofstream log("log.txt") und fertig. Streams sind halt sehr angenehm. Logging ist auch eine der wenigen Sachen wo ich mich evtl. für den Einsatz von Makros erwärmen kann da automatisches Mitloggen von File und Zeile eben doch angenehm ist. Man kann sich natürlich alles Mögliche einfallen lassen, wie wärs z.B. mit sowas:

Code: Alles auswählen

log(ERROR() << "foo " << 42);
Ein Makro log() dass eine entsprechende Funktion mit __FILE__ und __LINE__ aufruft die vielleicht für die verschiedenen Typen ERROR() und WARNING() überladen ist die selbst eben jeweils Streamoperationen unterstützen.
Oder einfach:

Code: Alles auswählen

log << ERROR("foo " << 42);
Das ließe sich direkt in eine Ausgabe auf einen Stream übersetzen. Prinzipiell fallen mir da alle 5 min. neue Möglichkeiten ein^^

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 17:17
von Chromanoid
MMh habt ihr schon mal gesehen was man mit Log4J bzw. java.util.logging und so machen kann? Die Komplexität von Logging sollte man nicht unterschätzen. Man sollte z.B. in der lage sein, pro Modul bzw. Klasse in unterschiedliche Logs zu schreiben ohne das im Code angeben zu müssen. Z.B. kann es im Produktiv-Betrieb sinnvoll sein, Meldungen eines bestimmten Moduls bestimmter Warnstufe per Email zu versenden etc. Das Ausgabeformat sollte auch konfigurierbar sein XML, HTML, TXT usw. Es gibt sowas wie log4j bestimmt auch für C++.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 01.06.2011, 17:19
von CodingCat
Ja, hier sind Makros ausnahmsweise wirklich Gold wert, __LINE__ und __FILE__ machen das Leben einfach enorm leichter. Der globale std::ofstream ist halt wieder extrem problematisch in Bezug auf Initialisierungsreihenfolge. Deshalb ist das für mich keine Alternative zur lokal definierten statischen Variable, Singleton muss ja deshalb nicht (und sollte womöglich auch, wie eben angemerkt, nicht) sein.

Den Vorteil gegenüber (mehreren) globalen Funktionen sehe ich darin, dass der immer notwendige zentrale Zugriffspunkt auf das Bezugsobjekt automatisch dafür sorgt, dass dieses Objekt dort auch tatsächlich erzeugt wird. Bei mehreren Overloads einer globalen Funktion müsste derartiges Verhalten schon wieder in alle Funktionen kopiert werden.

Nachtrag: Krishty merkte gerade an, dass am Ende immer Buchstaben ausgegeben werden müssen, und die entsprechende zugrundeliegende Funktion dann problemlos die Initialisierung übernehmen kann.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 12:37
von Brainsmith
Huch, hab mich ganz schön erschreckt, als ich hier reingeschaut hab.. So viele neue Posts.

Also.. Das Makro benutze ich auch nicht. Ich habe das nur geschrieben, um klarzumachen, wie der Singleton definiert ist. Und nun mal eine andere Frage:

Ich habe das Gefühl, dass hier mehrere Leute Singletons nicht mögen. Warum ist das so?
In meinem Falle geht es um eine Sound Engine. Ich will halt nicht, dass jemand versucht, das Ding zweimal zu initialisieren.

Wo wir aber gerade dabei sind. Gibt es Performance-Nachteile bei nem statischen Singleton? Das wäre für mich das einzige Argument, was zählt.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 12:43
von Schrompf
Brainsmith hat geschrieben: Ich habe das Gefühl, dass hier mehrere Leute Singletons nicht mögen. Warum ist das so?
In meinem Falle geht es um eine Sound Engine. Ich will halt nicht, dass jemand versucht, das Ding zweimal zu initialisieren.
Und wem bitte soll das "aus Versehen" passieren? Mal ganz davon abgesehen, dass auf allen aktuellen Betriebssystemen zwei parallele Sound Engines stressfrei möglich sind.

Zum Thema "nicht mögen": ich kann nicht für die anderen sprechen, aber ich persönlich habe schon mehrmals Singletons wieder entfernen müssen, weil der "Zu aller Zeit nur diese eine Instanz" einem halt immer irgendwann auf die Füße fallen wird. Und aus heutiger Sicht kann ich nur noch den Kopf schütteln, wenn Leute extra Arbeit und Code auf eine Aufgabe verschwenden, um einen ernsthaften Designfehler in ihrer Softwarearchitektur festzunageln. Wenn es momentan schön bequem ist, eine globale Instanz zu haben, na dann sollen sie halt eine anlegen.

Singletons würde ich nur in dem Fall benutzen, wo der Konstruktor nach Bedarf beim ersten Aufruf laufen soll, ohne dass ich mit normalem Code vorher was einrichten kann.
Wo wir aber gerade dabei sind. Gibt es Performance-Nachteile bei nem statischen Singleton? Das wäre für mich das einzige Argument, was zählt.
Ja, es kostet bei jedem get() die Rechenzeit, auf Existenz der Instanz zu prüfen, um sie notfalls anlegen zu können. Bei einer "static" Instanz erzeugt der Compiler diesen Code für Dich, aber die Rechenzeit ist dieselbe. Wenig, aber nicht Null.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 12:48
von Krishty
Brainsmith hat geschrieben:Gibt es Performance-Nachteile bei nem statischen Singleton? Das wäre für mich das einzige Argument, was zählt.
Dann triffst du höchstwahrscheinlich alle deine Entwurfsentscheidungen auf völlig verkehrter Grundlage.

Was das Singleton an sich angeht: Wenn du eine globale Abhängigkeit hast, ändert sich daran auch nichts, wenn du sie in einer Funktion verpackst. Du machst dir nur ein bisschen mehr Arbeit, aber die ist Verschwendung weil die Abhängigkeit an sich bleibt. Was jedoch wiederum dafür spricht ist, wie erwähnt, die undefinierte Initialisierungsreihenfolge bei globalen Instanzen.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 12:57
von Brainsmith
Schrompf hat geschrieben:
Brainsmith hat geschrieben: Ich habe das Gefühl, dass hier mehrere Leute Singletons nicht mögen. Warum ist das so?
In meinem Falle geht es um eine Sound Engine. Ich will halt nicht, dass jemand versucht, das Ding zweimal zu initialisieren.
Und wem bitte soll das "aus Versehen" passieren? Mal ganz davon abgesehen, dass auf allen aktuellen Betriebssystemen zwei parallele Sound Engines stressfrei möglich sind.
Man muss immer vom dümmsten User ausgehen, den man sich denken kann. =D

Wo wir aber gerade dabei sind. Gibt es Performance-Nachteile bei nem statischen Singleton? Das wäre für mich das einzige Argument, was zählt.
Ja, es kostet bei jedem get() die Rechenzeit, auf Existenz der Instanz zu prüfen, um sie notfalls anlegen zu können. Bei einer "static" Instanz erzeugt der Compiler diesen Code für Dich, aber die Rechenzeit ist dieselbe. Wenig, aber nicht Null.
Hmm.. da habeich wohl etwas falsch verstanden. Ich dachte, wenn der Singleton statisch ist, wird der direkt zu Beginn auf den Stack gelegt und dann einfach nur imemr wieder geholt, falls notwendig.
In dem Fall ist es aber immernoch Meckern auf hohem Niveau. Wie oft greift man schon per GetInstance darauf zu? Im Regelfall passiert das dann auch nicht zur Laufzeit, sondern zur Ladezeit. Da kann ich die paar Abfragen noch verkraften.
Krishty hat geschrieben:
Brainsmith hat geschrieben:Gibt es Performance-Nachteile bei nem statischen Singleton? Das wäre für mich das einzige Argument, was zählt.
Dann triffst du höchstwahrscheinlich alle deine Entwurfsentscheidungen auf völlig verkehrter Grundlage.
Okay, ich bin ja lernbereit. Bitte kläre mich auf. Ich sehe den Punkt einfach nicht. Das, was zählt, ist Performance. Dabei ist es mir bisher völlig egal gewesen, ob etwas mal nicht objektorientiert war oder ob der Code für andere nicht leserlich ist. Dafür gibts ja auch Kommentare. Und schlechter wartbar ist der Code dadurch auch nicht. Also wäre es nett, wenn du da ein wenig ins Details gehen könntest.

Ps: Der letzte Teil hört sich evtl ein wenig zickig an. Ist nicht so gemeint. Ich meine das schon ernst, was ich da schreibe. =D

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 13:17
von Krishty
Brainsmith hat geschrieben:Okay, ich bin ja lernbereit. Bitte kläre mich auf. Ich sehe den Punkt einfach nicht. Das, was zählt, ist Performance. Dabei ist es mir bisher völlig egal gewesen, ob etwas mal nicht objektorientiert war oder ob der Code für andere nicht leserlich ist. Dafür gibts ja auch Kommentare. Und schlechter wartbar ist der Code dadurch auch nicht. Also wäre es nett, wenn du da ein wenig ins Details gehen könntest.

Ps: Der letzte Teil hört sich evtl ein wenig zickig an. Ist nicht so gemeint. Ich meine das schon ernst, was ich da schreibe. =D
Es gibt generell nur einen Punkt, wo Leistung ein Entscheidungskriterium ist: Nämlich, wenn du einen Algorithmus für die Lösung deines Problems aussuchst; und dann ist die Leistung in Laufzeitverhalten zu bewerten. Ansonsten geht es fast immer darum, das Problem so einfach wie möglich (so wenig komplex wie möglich, mit so wenig Quelltext wie möglich, mit so wenig Aufwand wie möglich) zu lösen. Einen Algorithmus zu wählen, der dein Problem in O(n×log(n)) löst statt in O(n²) wird dir mehr Leistung bringen als alle anderen Optimierungen, die du unter Einbußen von Wartbarkeit, Lesbarkeit und – vor allem – Zeit jemals zusammenschaben kannst, zusammen.

Und wenn es dann doch noch zu langsam ist, dann nicht wegen irgendeinem Singleton sondern wegen dem einen Prozent deines Quelltexts, der die innerste Schleife ausmacht. Den kannst du dann oft immernoch optimieren ohne den Rest kaputtzumachen. Oft ist es dann aber auch so, dass die simpelste Lösung am schnellsten abgearbeitet wird.

Ist natürlich nur eine Faustregel. Wenn man im Embedded-Bereich Pixel zusammenschabt oder auf der GPU hunderte Recheneinheiten füttern muss, verhält sich das u.U. kontraintuitiv (weil das übliche Bild vom Laufzeitverhalten durch Speicherlatenzen, Branching oder Flaschenhälse bei bestimmten Vorgängen verzerrt wird – oder weil die Compiler einen feuchten Kehricht wert sind). Wenn du aber bei einem normalen PC-Spiel alle deine Entscheidungen zeilenmäßig nach Leistung fällst, steuerst du langfristig auf eine Katastrophe zu.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 14:39
von Brainsmith
Krishty hat geschrieben:
Brainsmith hat geschrieben:Okay, ich bin ja lernbereit. Bitte kläre mich auf. Ich sehe den Punkt einfach nicht. Das, was zählt, ist Performance. Dabei ist es mir bisher völlig egal gewesen, ob etwas mal nicht objektorientiert war oder ob der Code für andere nicht leserlich ist. Dafür gibts ja auch Kommentare. Und schlechter wartbar ist der Code dadurch auch nicht. Also wäre es nett, wenn du da ein wenig ins Details gehen könntest.

Ps: Der letzte Teil hört sich evtl ein wenig zickig an. Ist nicht so gemeint. Ich meine das schon ernst, was ich da schreibe. =D
Es gibt generell nur einen Punkt, wo Leistung ein Entscheidungskriterium ist: Nämlich, wenn du einen Algorithmus für die Lösung deines Problems aussuchst; und dann ist die Leistung in Laufzeitverhalten zu bewerten. Ansonsten geht es fast immer darum, das Problem so einfach wie möglich (so wenig komplex wie möglich, mit so wenig Quelltext wie möglich, mit so wenig Aufwand wie möglich) zu lösen. Einen Algorithmus zu wählen, der dein Problem in O(n×log(n)) löst statt in O(n²) wird dir mehr Leistung bringen als alle anderen Optimierungen, die du unter Einbußen von Wartbarkeit, Lesbarkeit und – vor allem – Zeit jemals zusammenschaben kannst, zusammen.

Und wenn es dann doch noch zu langsam ist, dann nicht wegen irgendeinem Singleton sondern wegen dem einen Prozent deines Quelltexts, der die innerste Schleife ausmacht. Den kannst du dann oft immernoch optimieren ohne den Rest kaputtzumachen. Oft ist es dann aber auch so, dass die simpelste Lösung am schnellsten abgearbeitet wird.

Ist natürlich nur eine Faustregel. Wenn man im Embedded-Bereich Pixel zusammenschabt oder auf der GPU hunderte Recheneinheiten füttern muss, verhält sich das u.U. kontraintuitiv (weil das übliche Bild vom Laufzeitverhalten durch Speicherlatenzen, Branching oder Flaschenhälse bei bestimmten Vorgängen verzerrt wird – oder weil die Compiler einen feuchten Kehricht wert sind). Wenn du aber bei einem normalen PC-Spiel alle deine Entscheidungen nach Leistung fällst, steuerst du langfristig auf eine Katastrophe zu.

Ich hab mich vielleicht etwas drastisch ausgedrückt. Natürlich ist Wartbarkeit ein Kriterium, wie auch die Geschwindigkeit, in der der Code geschrieben wird. Bei einem Singleton hält sich das natürlich auch in Grenzen.
Ich glaube aber, ich habe den Punkt gefunden, wo unsere Meinungen differieren:
Es gibt generell nur einen Punkt, wo Leistung ein Entscheidungskriterium ist: Nämlich, wenn du einen Algorithmus für die Lösung deines Problems aussuchst
Die Sache ist dann doch eher, was man als Problem definiert. Ich sehe es meist so, dass alles, was ich programmiere in gewisser Weise ein Problem ist, weshalb diese Regel auch fast immer greift. Andererseits ist mir natürlich auch bewusst, was du meinst (Optimieren am falschen Ende vermeiden). Eine Frage ist aber auch: Was ist angenehmer: Im Nachhinein nochmal über den Code zu schauen und Optimierungen vorzunehmen oder den Code direkt so zu schreiben, dass solche Schritte unnötig sind. Dadurch ergibt sich mir dann die Folgefrage, welche Methode letztendlich schneller ist, wenn man die jeweilge Methde gwöhnt ist.
Scheinbar wird es als Axiom angesehen, dass der eine Workflow besser ist, als der andere. Falls jemand einen repräsentativen Artikel zum Thema hat, wäre ich sehr dankbar. Nur weil ein Ansatz für viele gilt, bedeutet dies nicht automatisch, dass er für alle richtig ist.

Zusätzlich dazu fühle ich mich immer furchtbar, wenn ich Code geschrieben habe, von dem ich weiß, dass er schneller sein könnte. Da möchte ich am liebsten wild mit einem Auge zucken und alles neu schreiben. :D
Wenn du aber bei einem normalen PC-Spiel alle deine Entscheidungen zeilenmäßig nach Leistung fällst, steuerst du langfristig auf eine Katastrophe zu.
Naja, ich treffe die Entscheidungen natürlich nicht zeilenmäßig, sondern problemmäßig nach Leistung (natürlich nur nach meinem doch recht.. sagen wir mal beschränkten Wissen).
Und tatsächlich gibt es auch Plattformen, wo man absolut effizient programmieren muss, wie zum Beispiel den Nintendo DS, wenn man da was rausholen will.
Ich habe mit dieser Einstellung in zwei kommerziellen Projekten gearbeitet und keine Probleme damit gehabt. Weder zeitlich, noch hat jemand die Lesbarkeit meines Codes bemängelt.

ich schließe natürlich die Möglichkeit nicht aus, dass wir gnadenlos aneinander vorbei schreiben und wir zB Sachen wie Lesbarkeit, Wartbarkeit etc. unterschiedlich definieren. Zumindest der Lesbarkeitsbegriff ist doch eher schwammig.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 17:54
von dot
Auf der einen Seite argumentierst du dass für dich nur rohe Performance zählt, auf der anderen Seite hast du bei einer typischen Implementierung des Singleton Pattern (z.B. Meyers Singleton) wie Schrompf schon sagte bei jedem Zugriff auf den Singleton infolge der statischen Variable mit gewissem Overhead zu rechnen (der Compiler muss ja Code einbaun der checked ob die Variable schon initialisiert wurde). Und dabei ist das Ding noch nichtmal annähernd Thread-Safe.

Wie schon gesagt: Das Hauptproblem von Singleton ist dass es praktisch immer für eine globale Instanz missbraucht wird. Manche nennen es sogar eine "objektorientierte Lösung für eine globale Variable" und solche Dinge, als ob es durch eine nette Verpackung besser würde. Genau dafür war Singleton per Definition nie gedacht. Ich hab sicher schon hunderte Singletons gesehn und jedes einzelne davon war ein grober Designfehler, was tut man nicht alles für etwas vermeintliche Bequemlichkeit? Singleton verschleiert Abhängigkeiten. Aber nur weil du sie nicht siehst heißt das noch lange nicht dass sie nicht da sind. Sogar rein theoretische Beispiele für den korrekten Einsatz von Singleton sind extrem rar und selbst dort findet man praktisch immer genug Gegenargumente und bessere Alternativen.

Singletons sind wie Krebs: Wenn du merkst dass du sie hast ist es meistens schon zu spät, denn das Singleton hat bereits überall in deinen Code metastasiert.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 19:14
von Chromanoid
Singletons sind dann sehr nützlich, wenn man Dienste per Dependency Injection flexibel in einem System nutzen möchte. Das klassische Singleton mit statischer Variable für die Instanz im Kontext einer Sprache wie C++ ist da vielleicht nicht ganz so toll. Naja vielleicht ist es auch kein Singleton mehr, wenn es über eine Registry injected wird, aber zumindest im JSR 330 wird es so genannt...

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 20:21
von Brainsmith
dot hat geschrieben:Auf der einen Seite argumentierst du dass für dich nur rohe Performance zählt, auf der anderen Seite hast du bei einer typischen Implementierung des Singleton Pattern (z.B. Meyers Singleton) wie Schrompf schon sagte bei jedem Zugriff auf den Singleton infolge der statischen Variable mit gewissem Overhead zu rechnen (der Compiler muss ja Code einbaun der checked ob die Variable schon initialisiert wurde). Und dabei ist das Ding noch nichtmal annähernd Thread-Safe.
Zugegeben, das wirkt doch schon ein wenig konfus. Ich habe schlichtweg nicht gewusst, dass bei jedem Zugriff Overhead entsteht. Ich hab gedacht, dass nur dann Overhead entsteht, wenn man GetInstance() aufruft. Das wäre dann zum Ladezeitpunkt gewesen, wo Performance einfach mal keine Rolle spielt. Da muss ich was falsch gelesen haben...

In dem Fall hast du natürlich vollkommen recht. Ein Bekannter wollte die Soundengine benutzen und hat mich gebeten einen statischen Singleton zu nutzen. Gefragt, getan. Ich werd das noch mal bequatschen müssen.
Der Weg zur Hölle ist mit guten Vorsätzen geebnet. Bestes Beispiel meinerseits. :D

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 02.06.2011, 22:05
von Aramis
aber zumindest im JSR 330 wird es so genannt...
Ich sag's ja echt ungern, aber im Titel ist ein C++-Tag :-)

Die Idee, Singletons durch DI der benoetigten Interfaces de-fakto loszuwerden, ist aber eigentlich eine ziemlich elegante – aber wenn es in der C++–Welt ueblich waere, jeder Funktion ihre kompletten Abhaengigkeiten als Parameter zu geben, haetten wir sowieso eine ganze Menge Probleme weniger.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 12:37
von dot
Chromanoid hat geschrieben:Singletons sind dann sehr nützlich, wenn man Dienste per Dependency Injection flexibel in einem System nutzen möchte.
Was genau meinst du damit? Damit würde man doch die Nachteile beider Patterns kombinieren, oder überseh ich da was!?
Brainsmith hat geschrieben:Ich hab gedacht, dass nur dann Overhead entsteht, wenn man GetInstance() aufruft.
Natürlich entsteht nur dann Overhead. Aber die übliche Vorgehensweise ist eben genau immer über GetInstance() an die Instanz zu kommen!?
Aramis hat geschrieben:Die Idee, Singletons durch DI der benoetigten Interfaces de-fakto loszuwerden, ist aber eigentlich eine ziemlich elegante [...]
Wenn du mich fragst ist das der einzig vernünftige Weg, Singletons sind imo jedenfalls keine Lösung. Aber ja, leider hat kaum einer den Singleton Pattern wirklich verstanden und darum verwendet ihn jeder überall obwohl er eigentlich wenn überhaupt ein extremes Nischendasein fristen sollte.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 13:08
von Chromanoid
dot hat geschrieben:
Chromanoid hat geschrieben:Singletons sind dann sehr nützlich, wenn man Dienste per Dependency Injection flexibel in einem System nutzen möchte.
Was genau meinst du damit? Damit würde man doch die Nachteile beider Patterns kombinieren, oder überseh ich da was!?
Welche Nachteile meinst du denn?

Service
ServiceImplA (soll nur einmal pro Programm erzeugt werden -> "Singleton")
ServiceImplB (soll nur einmal pro Programm erzeugt werden -> "Singleton")

Konfigurations-Datei oder Modul-Klasse a'la Guice setzt ServiceImplB für Service

KlasseX benötigt Service und die Instanzen bekommen ServiceImplB injiziert.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 13:12
von Schrompf
Woher kommt denn da das "Soll nur einmal pro Programm erzeugt werden"? Das frage ich mich immer bei diesen Geschichten. Wenn Du nach Konfigdatei eine der beiden Klassen auswählen sollst, brauchst Du eine Factory. Die könnte dann auch das "nur einmal erzeugen" implementieren, ohne das man die Klasse selbst damit belasten müsste.

Das Reinreichen dieser Instanz in abhängige Module ist nach meiner Betrachtung dann schon ein anderes Thema - Standard Dependency Injection. Gute Sache, kann man so machen. Hat mit dem Thema "Singleton" aber nix zu tun.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 13:20
von Chromanoid
Schrompf hat geschrieben:Woher kommt denn da das "Soll nur einmal pro Programm erzeugt werden"? Das frage ich mich immer bei diesen Geschichten. Wenn Du nach Konfigdatei eine der beiden Klassen auswählen sollst, brauchst Du eine Factory. Die könnte dann auch das "nur einmal erzeugen" implementieren, ohne das man die Klasse selbst damit belasten müsste.
Naja wie ich schon eingangs erwähnte, wird in JSR 330 die Annotation, die Klassen als "Soll nur einmal pro Programm erzeugt werden" markiert, @Singleton genannt. Dass es sich dabei vielleicht nicht mehr um ein Singleton handelt, habe ich ja bereits oben angesprochen...

Dort findet man eine Erklärung zum "DI Singleton"
http://code.google.com/p/google-guice/wiki/Scopes

Code: Alles auswählen

@Singleton
public class InMemoryTransactionLog implements TransactionLog {
  /* everything here should be threadsafe! */
}
Und bezüglich der Factory: DI Frameworks sind ja oft auch eine Art Factory, aber eben noch viel mehr...

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 19:04
von dot
Chromanoid hat geschrieben:Service
ServiceImplA (soll nur einmal pro Programm erzeugt werden -> "Singleton")
ServiceImplB (soll nur einmal pro Programm erzeugt werden -> "Singleton")
Nur um das vielleicht nochmal klarzustellen: Singleton heißt nicht dass man von etwas nur eine Instanz braucht. Singleton sagt explizit dass es eine wesentliche Eigenschaft dieses Typs ist dass es, was auch immer passieren mag, um keinen Preis der Welt jemals und überhaupt irgendwie bis ans Ende aller Tage mehr als eine Instanz dieser Klasse geben darf. Genau das sicherzustellen ist die Aufgabe des Singleton Pattern (hence the name). Dass es nur eine Instanz mit einem globalen Zugriffspunkt gibt ist lediglich eine Konsequenz des Pattern. Man kann jetzt argumentieren inwiefern das eigentlich überhaupt den Grundfesten der OOP widerspricht, aber lassen wir das mal beseite so gibt es immer noch extrem selten einen Typen auf den das vielleicht zutrifft. In allen Fällen (und damit mein ich alle Fälle wo dies evtl. tatsächlich zutrifft, was schon fast jeden heute existierenden Singleton ausschließt) die ich bisher gesehen hab war man besser beraten keinen Singleton einzusetzen. Ich seh in Singleton daher jedenfalls ein typisches Antipattern.

Wenn du also aus deinem ServiceImplA einen Singleton machst dann sagst du damit nicht: "Ich brauch nur einen ServiceImplA" sondern du sagst "Es kann nie mehr als einen ServiceImplA geben denn das würde dem Konzept eines ServiceImplA widersprechen und das muss in der Schnittstelle dieses Typs so auch von vornherein ausgedrückt sein". Und genau da liegt das Missverständnis das uns 99.9999999% aller Singletons beschert...

Ich hab mir jetzt dieses guice Framework da nicht genau angeschaut aber dieses @Singleton schaut mir von der Semantik her eher nach einer globalen Variable als nach einem Singleton aus denn du könntest die Klasse ja theoretisch immer noch manuell Instanzieren wie du lustig bist, @Singleton sagt nur dem Framework dass es immer die selbe Instanz verwenden soll oder!?

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 20:14
von Chromanoid
genau. deswegen auch meine zweifel daran ob man das noch singleton nennen kann. der begriff "singleton" jedenfalls wird dank jsr 330 jetzt in vielen di frameworks für java und (dadurch auch in) .net benutzt. hier eine erklärung die eigentlich genau das sagt, was du dazu meinst: http://picocontainer.org/antipatterns/s ... ttern.html dennoch wird auch hier in der doku der begriff "singleton-like" eingesetzt :)

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 20:32
von dot
Naja, natürlich kann man es "Singleton" nennen (so bezeichnet man ursprünglich ja in der Mathematik einfach eine einelementige Menge), aber mit dem Singleton Pattern (um das es hier geht) hat das soweit ich das sehen kann absolut nichts zu tun.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 20:38
von Chromanoid
wenn man ein singleton darauf reduziert, dass immer nur eine instanz pro anwendung davon erzeugt werden darf, und eine annotation in zusammenarbeit mit einem di framework als geeignetes mittel für die sicherstellung dieser anforderung akzeptiert, dann kann man imo von einer modernen form des singletons sprechen. die eher technische Beschreibung für die Sicherstellung im gamma mit einer "Instance operation" über eine "class method"/"static member function" ist imo eher zu vernachlässigen. aber langsam wirds wirklich sehr offtopic :)

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 03.06.2011, 20:48
von dot
Chromanoid hat geschrieben:wenn man ein singleton darauf reduziert, dass immer nur eine instanz pro anwendung davon erzeugt werden darf, und eine annotation in zusammenarbeit mit einem di framework als geeignetes mittel für die sicherstellung dieser anforderung akzeptiert, dann kann man imo von einer modernen form des singletons sprechen.
Ok ja, dann kann man drüber diskutieren, wobei ich das doch immer noch als sehr grenzwertig sehen würd da der Typ sich nichtmehr drum kümmert wann und wo die eine Instanz erzeugt wird, aber egal ;)

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 11.09.2011, 02:52
von BeRsErKeR
Ich kann diesen ganzen Hass gegen Singletons nicht nachvollziehen. Ich meine, ist etwas von Grund auf "böse", nur weil es an vielen Stellen unnütz oder der "falsche Weg" ist? Ich kann solche Verteufelungen verstehen, wenn bestimmte Ansätze etwas extrem verschlechtern wie Sicherheit, Lesbarkeit usw, aber ein Singleton ist doch nun wirklich nichts was man derart schlecht reden muss. Da gibt es weitaus schlimmere Dinge. Ich habe irgendwie den Eindruck, dass irgendwann mal jemand anfing Singletons zu verteufeln und nun viele mitmachen.

Ich persönlich nutze sehr viele Singletons in meinem Projekt, wohlwissend, dass es globale Instanzen auch tun würden (wobei ich allerdings sehr wahrscheinlich wirklich ein Problem mit der Initialisierungsreihenfolge bekommen könnte). Sie erfüllen die Anforderungen, die ich habe und da ist mir scheißegal wozu sie mal entworfen wurden. Ich glaube ein bischen Gewohnheit und angeeigneter Stil schwingt immer mit und ich habe lange Zeit einen großen Bogen um globale Variablen gemacht, womöglich aus den gleichen Gründen, warum heute viele Singletons so verteufeln: Irgendwo stand, dass es böse ist. Aus dieser Zeit habe ich wohl immer noch die Gewohnheit an Singletons anstatt globaler Variablen und das ist auch ein Grund warum ich extrem negative oder auch extrem positive Meinungen zu etwas sehr vorsichtig und kritisch beäuge.

Ich sehe nicht ein nun meine Gewohnheiten und Projekte komplett umzukrempeln, nur weil Singletons angeblich der falsche Weg sind. Gäbe es einen wirklich ausschlaggebenden Grund, würde ich nicht zögern, aber ich konnte bis heute noch nie feststellen, dass Singletons einen so negativen Einfluss haben, dass es gerechtfertigt wäre, sie überall zu ersetzen oder nicht mehr zu nutzen. Ich bin natürlich dafür, darauf hinzuweisen, dass es anders besser geht oder bestimmte Schwachstellen aufzuzeigen, aber einige Beiträge hier (besonders von dot) grenzen ja gefühlt schon fast an Hasspredigten.

Das Argument (von Schrompf wenn ich nicht irre) "Zeit zu investieren, in Dinge die keinen Vorteil bringen" kann ich noch am ehesten nachvollziehen bzw. es würde mich am ehesten von allen anderen dazu bringen auf Singletons zu verzichten. Allerdings sind 3 Zeilen Code nicht unbedingt eine Menge, die ich als wirklichen Aufwand betrachte. Wenn ich mich von meinem letzten Floh, der mir in den Kopf gesetzt wurde, nämlich "alles globale in OO ist böse", erholt habe, werde ich die Singletons vielleicht auch nach und nach durch globale Instanzen ersetzen (wenn möglich), aber bis dahin überlege ich mir lieber 3 mal ob ich mich von Dingen distanziere, nur weil sie bei vielen Leuten scheinbar unten durch sind.

Habe die Ehre

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 11.09.2011, 03:25
von CodingCat
BeRsErKeR hat geschrieben:Ich persönlich nutze sehr viele Singletons in meinem Projekt, wohlwissend, dass es globale Instanzen auch tun würden (wobei ich allerdings sehr wahrscheinlich wirklich ein Problem mit der Initialisierungsreihenfolge bekommen könnte).
Dann sind es doch bereits globale Instanzen. ;-)

Singleton heißt, dass von deiner Klasse nur ein einziges Objekt angelegt werden kann, werden darf. Dass dieses einzige Objekt dadurch üblicherweise nebenbei global verfügbar wird, liegt daran, dass Singletons üblicherweise über globale Instanzen implementiert werden. Ob deine globale Instanz jetzt als static in einer statischen Methode vorliegt oder als freie globale Variable außerhalb deiner Klasse definiert wurde, wirkt sich auf die Initialisierungsreihenfolge aus, spielt aber von der globalen Semantik her keine weitere Rolle.
Auch bei einer globalen Instanz ohne das Singleton-Muster wäre deshalb aufgrund der Initialisierungsreihenfolge die static-Variable in einer freien Funktion der freien globalen Instanzvariable gegebenenfalls vorzuziehen.

Um es kurz zu machen: Es geht hier nicht darum, wo genau deine Instanz definiert ist, sondern es geht um den eigentlichen Aspekt des Singletons, die Konstruktionsbeschränkung. Der Grund, warum Singletons praktisch immer eine schlechte Wahl sind, liegt darin, dass diese Konstruktionsbeschränkung Klassen praktisch immer nur unnötig nutzloser macht. Nehmen wir wieder das Beispiel des Loggings her, zunächst die Singletonvariante:

Code: Alles auswählen

class log_file : public noncopyable
{
   file m_file;

   // Hide C~tor & D~tor
   log_file(const string &filename)
      : m_file(filename, overwrite) { }
   ~log_file() { }
public:
   static log_file& instance()
   {
      static log_file log("log.txt");
      return log;
   }

   void write(...) { ... }
};
Über log_file::instance().write(...) lässt sich ins zentrale Logbuch schreiben. Aber das Singleton macht die Sache nur überflüssig kompliziert. Schlimmer, wenn wir jetzt ein weiteres Logbuch für einen speziellen Teilprozess bräuchten, müssten wir die Klasse duplizieren, damit sie mit dem Singleton-Muster konform bleibt. Das ist das absolute Gegenteil jeglicher Objektorientierung.

Ohne uns Gedanken über Singletons zu machen, haben wir exakt dasselbe Verhalten, nur einfacher, und wiederverwendbar, auf folgende Weise:

Code: Alles auswählen

class log_file : public noncopyable
{
   file m_file;

public:
   log_file(const string &filename)
      : m_file(filename, overwrite) { }
   ~log_file() { }

   void write(...) { ... }
};

log_file& default_log()
{
   static log_file log("log.txt");
   return log;
}
Was ist daran schlechter? Nichts. Was ist daran besser? Über global_log().write(...) lässt sich wesentlich kürzer und aussagekräftiger in das zentrale Logbuch schreiben. Brauchen wir weitere globale Logbücher, können wir einfach weitere freie Funktionen AN BELIEBIGEN STELLEN (auch fernab der log_file-Klasse) hinzufügen. Brauchen wir ein Logbuch nur lokal, können wir lokal mal eben eine log_file-Instanz anlegen, ohne überhaupt zusätzliche Funktionen zu benötigen. Man beachte, dass die Initialisierungsreihenfolge exakt dieselbe wie beim Singleton ist.

Fazit: Wir haben durch weniger Design-Aufwand die Komplexität verringert und die Funktionalität wesentlich verbessert, ohne irgendeinen Nachteil einzugehen.
BeRsErKeR hat geschrieben:Ich persönlich nutze sehr viele Singletons in meinem Projekt, [...] sie erfüllen die Anforderungen, die ich habe und da ist mir scheißegal wozu sie mal entworfen wurden.
Klar kannst du auch mit Singletons erfolgreich programmieren, du programmierst dann eben schlichtweg nicht objektorientiert. ;-) Es gibt nur keinen Grund, erhöhte Komplexität einzugehen, um sich kostenlose Funktionalität durch Mehraufwand zu verbauen, ohne dabei irgendetwas zu gewinnen.
BeRsErKeR hat geschrieben:Wenn ich mich von meinem letzten Floh, der mir in den Kopf gesetzt wurde, nämlich "alles globale in OO ist böse", erholt habe
Das hat prinzipiell gar nichts mit Objektorientierung zu tun, globale Variablen/Operationen/Objekte/Zustände haben mitunter folgende Nachteile: Unabsehbare Seiteneffekte, undurchsichtige Abhängigkeiten, geringere Flexibilität, geringe Wiederverwendbarkeit.
Insbesondere die ersten beiden Punkte sind eine sehr ernste Sache: Wenn nicht klar ist, welche Variablen/Objekte/Zustände durch eine Operation verändert werden, wird es schwierig bis unmöglich, Annahmen über aktuelle Werte und Zustände zu machen, Invarianten zu erhalten sowie anderweitige effektive Konsistenzerhaltung zu betreiben.
Wenn nicht klar ist, welche Module/Operationen von welchen anderen Modulen/Operationen abhängen, ist es sehr leicht, in zyklische Abhängigkeiten zu verfallen, dies reicht von undefiniertem Verhalten mangels korrekter isolierter Initialisierbarkeit bis hin zu undurchschaubaren Endlosrekursionen bei der globalen Verteilung von Ereignissen.

Beim oben beschriebenen Beispiel des Logbuchs ist das keine große Sache, das Logbuch nutzt selbst keine weiteren globalen Objekte, wodurch keine unabsehbaren Seiteneffekte auftreten können, auch die Abhängigkeiten des Logbuchobjekts sind klar. Sobald globale Operationen/Objekte jedoch beginnen, andere globale Variablen/Operationen/Objekte/Zustände zu nutzen, führst du mit jeder weiteren globalen Abhängigkeit eine weitere Ebene der Undurchsichtigkeit ein.

Re: [C++] Speicherfreigabe bei statischem Singleton

Verfasst: 11.09.2011, 04:26
von dot
Ich denke, Cat hat es schön auf den Punkt gebracht :)

Das Problem ist nicht der richtige Singleton Pattern an sich, sondern der "Singleton" Pattern, eben jene bunte Verpackung für globale Variablen, für die Singleton meist gehalten wird.
Selbst wenn wir die ganzen Probleme globaler Variablen (allem voran die Verschleierung von Abhängigkeiten), die natürlich nicht verschwinden (die Verpackung ändert ja schließlich nichts am Inhalt), mal ignorieren, birgt die Verwendung des Pattern als "Ersatz" für eine globale Variable nur noch zusätzliche Nachteile in sich, ist dabei aber völlig frei von Vorteilen, was kaum verwunderlich ist. Denn dafür ist der Pattern einfach nicht gedacht, war er nie und wird er nie sein.
Der Zweck des Singleton Pattern ist, sicherzustellen, dass von einem Typ unter keinen Umständen, bis ans Ende der Zeit jemals und überhaupt, mehr als exakt eine Instanz erzeugt wird (hence the name). Der Singleton Pattern dient dazu, genau das und nur das auszudrücken, das zu einer Eigenschaft des Typs selbst zu machen. Steht genau so auch auf der ersten Seite des entsprechenden Abschnittes in dem Buch, wo Singleton das erste Mal beschrieben wurde. Wenn man so will, zählen die drei Sätze dort wohl zu den am meisten missverstandenen Worten der Softwareentwicklung (Zugegeben: Die originale Formulierung ist vielleicht etwas unglücklich gewählt). Die Tatsache dass es eine globale Instanz gibt, ist nur eine Konsequenz, nicht aber der Zweck des Singleton Pattern. (important difference here)
Ob das jetzt gut oder schlecht ist, inwiefern das überhaupt dem Grundgedanken von Objektorientiertheit widerspricht, darüber könnte man nun diskutieren. Ist hier aber irrelevant, denn um dieses Pattern gehts ja garnicht.
Fakt ist, dass Anwendungfälle für einen richtigen Singleton extrem selten sind. Ich hab, in all der Zeit die ich nun auf Mutter Erde wandle, noch praktisch keinen gesehen. Selbst in den Fällen, wo man ernsthaft hätte drüber reden können, einen Singleton zu verwenden, hat sich für mich immer noch eine bessere Lösung gefunden.
Das Problem ist nicht, dass irgendwann mal jemand anfing, Singletons zu verteufeln. Das Problem ist, dass irgendwann mal jemand es für eine gute Idee hielt, seine globalen Variablen als Singletons zu tarnen und dann alle mitgemacht haben. Denn Patterns waren grad voll modern und wenn wir brav für alles einen Pattern benutzen, dann kann es ja eigentlich nurmehr toll sein. Und "Singleton" ist natürlich ein sehr praktisches Pattern, bewahrt es einen doch davor, sich tatsächlich Gedanken über Design machen zu müssen. Ich hab einfach meine paar globalen Instanzen, jeder kennt jeden und kann daher ständig auf alles zugreifen. Angenehmer geht's doch eigentlich gar nicht mehr!? Ohne "Singleton" müssten wir uns doch wirklich überlegen, was wann wie voneinander abhängt, wie Objekte in Beziehung treten, interagieren und ob das alles so eigentlich semantisch sinnvoll ist. Am Ende würden wir sogar viel Zeit damit verschwenden, über unser Design zu reflektieren und es zu refactoren, denn ohne "Singleton" tauchen Abhängigkeiten plötzlich in den Schnittstellen auf und wer will das schon, denn so ein Design wäre am Ende noch flexibel...

Meine Meinung basiert jedenfalls auf meiner Erfahrung und nicht auf Dingen, die ich irgendwo mal gelesen hab. Und meine Erfahrung ist, dass der Verzicht auf Singleton eine gute Guideline ist, die einen praktisch immer in Richtung gutes Design zwingt. Die Wahrscheinlichkeit, dass Singleton tatsächlich eine gute Lösung gewesen wäre, ist jedenfalls in etwa so hoch wie die, dass der Hai, der mich, am Tag da ich von meinem zweiten Lottogewinn erfahre, frisst, von einem Blitz getroffen wird und überlebt.

Btw: Ich hege keinen Hass, schon gar nicht gegen ein Software Pattern. Ich hab nur strong Opinions, was manche Dinge betrifft. Von mir aus darfst du machen, was du willst. Ich kann dir nur wünschen, dass du niemals zu dem Punkt kommst, wo du auf einmal doch gern zwei Instanzen hättest. Denn dann kannst du jede einzelne Metastase deines Singleton suchen und herausoperieren. Wobei: Ist eigentlich eine sehr heilsame Erfahrung, auf zweierlei Art ;)