globale variable oder nicht?
-
dot schrieb:
Singleton und globale Variablen sind zwei völlig orthogonale Konzepte.
Sie mögen unterschiedliche Konzepte sein, doch wurden letztere in den Projekten in denen ich gearbeitet habe nicht selten für das gleiche verwendet. z.B. für das halten einer globalen Konfiguration (mit schönen Fehlereffekten wegen Abhängigkeiten und Linkreihenfolgen die sich geändert hatten)...
dot schrieb:
Das einzige was Singletons und globale Variablen gemeinsam haben ist, dass man praktisch immer, wenn man denkt, dass ein Singleton oder eine globale Variable angebracht wäre, falsch liegt; ganz besonders bei Singleton und ziemlich sicher auch in diesem Fall...
Bei globalen Variablen ist dies in der Regel ebenso falsch (Ich würde im Zweifel sogar ein Singleton vorziehen, da die Initialisierung hier "definierter" abläuft).
Ich verwende auch in Projekten vereinzelt Singletons, weil mir für den Anwendungsfall keine bessere Lösung eingefallen ist (Rechte zum Angemeldeten Benutzer, die in der Regel nur einmalig initialisiert werden, und an sehr vielen Programmstellen abgefragt werden; Ebenso nutzen wir das Application-Objekt von der VCL [Merkt sich u.a. die Aufrufparameter], das man sowohl als globale Variable als auch als Singleton umsetzen kann - vermutlich ist es ersteres, habe es aber nicht nachgeprüft).
-
Wir verwenden gerade für solche globalen Konfigurationen auch Singletons.
@asc Aus deiner Bemerkung dazu schließe ich, dass ihr dafür jetzt keine Singletons mehr verendet. Wie macht man es dann? Mir ist hier dazu nichts besseres als Singleton (oder eben globale Variable) eingefallen.
-
Ich würde globale Variablen einfach so verpacken und gut:
std::vector<Item>& globalItems() { static std::vector<Item> items; return items; }Solange man den globalen ZUgriff nur möglichst lokal verwendet und abkapselt, wo ist das Problem.
-
asc schrieb:
dot schrieb:
Singleton und globale Variablen sind zwei völlig orthogonale Konzepte.
Sie mögen unterschiedliche Konzepte sein, doch wurden letztere in den Projekten in denen ich gearbeitet habe nicht selten für das gleiche verwendet.
Naja, das machts aber eben noch lange nicht gut oder richtig...
asc schrieb:
Bei globalen Variablen ist dies in der Regel ebenso falsch (Ich würde im Zweifel sogar ein Singleton vorziehen, da die Initialisierung hier "definierter" abläuft).
Wenn ich einfach nur wohldefinierte Initialisierungsreihenfolge brauch, dann kann ich auch einfach eine normale Funktion machen, die das entsprechende Objekt in Form einer statischen Variable instanziert und eine Referenz drauf zurückgibt, ich seh nicht, wieso genau da automatisch das Singleton Pattern benötigt würde!?
asc schrieb:
Ebenso nutzen wir das Application-Objekt von der VCL [Merkt sich u.a. die Aufrufparameter], das man sowohl als globale Variable als auch als Singleton umsetzen kann - vermutlich ist es ersteres, habe es aber nicht nachgeprüft).
So ein Application Objekt wäre imo evtl. sogar einer der seltenen Fälle, wo man tatsächlich drüber diskutieren könnte, ob das Singleton Pattern dabei angebracht wäre, da man es hier ausnahmsweise wirklich mit etwas zu tun hat, das zu seiner wesentlichen Eigenschaft hat, dass es nur einmal existiert.
asc schrieb:
z.B. für das halten einer globalen Konfiguration (mit schönen Fehlereffekten wegen Abhängigkeiten und Linkreihenfolgen die sich geändert hatten)...
Braunstein schrieb:
Wir verwenden gerade für solche globalen Konfigurationen auch Singletons.
Und mit genau welcher Begründung? Wieso genau muss um jeden Preis sichergestellt werden, dass die entsprechenden Typen hier und jetzt, für alle Zeit und überhaupt niemals je mehr als genau einmal instanziert werden? So lange du dafür kein Argument hast, hast du keinen Grund um einen Typen zu einem Singleton zu machen. Zugegeben, eine applikationsweite Konfiguration ist unter Umständen ein Grenzfall, wo man dafür und dagegen argumentieren kann und wo man auch nicht so oft tatsächlich ein Problem mit dem Singleton bekommen wird. Imo ist ein Singleton allerdings keine schöne Lösung.
Dass die Wiederverwendbarkeit von Code voller versteckter globaler Abhängigkeiten praktisch Null ist, ist euch bewusst, nehm ich mal an!?
-
dot schrieb:
asc schrieb:
Sie mögen unterschiedliche Konzepte sein, doch wurden letztere in den Projekten in denen ich gearbeitet habe nicht selten für das gleiche verwendet.
Naja, das machts aber eben noch lange nicht gut oder richtig...
Stimmt.
Aber wenn man davon absieht, das ein Singleton global nur eine Instanz hält, sehe ich dennoch nur wenige Unterschiede zwischen globalen Variablen, Singletons und Funktionen die eine statische Variable zurückliefert. Von den Grundprinzip hat man bei allen 3 Ansätzen ähnliche Anforderungen: Zugriff von mehreren Stellen auf einen bestimmten Kontent, der zur Laufzeit erhalten bleibt.
dot schrieb:
asc schrieb:
z.B. für das halten einer globalen Konfiguration (mit schönen Fehlereffekten wegen Abhängigkeiten und Linkreihenfolgen die sich geändert hatten)...
Braunstein schrieb:
Wir verwenden gerade für solche globalen Konfigurationen auch Singletons.
Und mit genau welcher Begründung? Wieso genau muss um jeden Preis sichergestellt werden, dass die entsprechenden Typen hier und jetzt und für alle Zeit jemals nie mehr als einmal instanziert werden?
In unseren Programm gibt es bezogen auf eine Programminstanz genau _einen_ Benutzer, mit seinen Rechten und benutzerspezifischen Einstellungen; Bei der Programmkonfiguration sieht es ähnlich aus. Nenn mir hier den Grund warum man unbedingt mehrere Instanzen braucht.
Ob ich hier eine Funktion mit statischer Variable oder ein Singleton anbiete nimmt sich für mich überhaupt nichts. Ein Singleton ist auch nichts anderes als eine statische Variable, wenn gleich die Schnittstelle per se nur eine Instanz anbietet.
Davon abgesehen gibt es auch Singletons die zwar eine Instanz eines bestimmten Typs halten, der Typ als solches aber seperat instanziert werden kann...
-
Braunstein schrieb:
@asc Aus deiner Bemerkung dazu schließe ich, dass ihr dafür jetzt keine Singletons mehr verendet. Wie macht man es dann? Mir ist hier dazu nichts besseres als Singleton (oder eben globale Variable) eingefallen.
Ich verwende weiterhin Singletons (wenn ich auch nicht sagen kann wie es in den vorherigen Firmen abläuft, hatte dort einiges zumindest auf die Variante mit der Funktion mit statischen Kontent geändert), aber versuche die Anzahl in Grenzen zu halten.
Im aktuellen Programm gibt es effektiv 4 globale Werte (unterschiedlich umgesetzt):
1. Ein Objektcache für Stammdaten [der eigentlich die DB-Zugriffe reduzieren sollte - den ich aber liebend gern entfernen würde, er macht imho mehr Ärger als er wirklich Nutzen bringt].
2. Daten zur aktuellen Anmeldung [Benutzername/Rechte]
3. Die Programmkonfiguration
4. Das VCL-Application ObjektNummer 2 ist definitiv als Singleton [Meyer-Singleton] umgesetzt (basiert auf meinen Mist), da ich hier keinen Grund für mehrere Instanzen sehe.
-
asc schrieb:
Aber wenn man davon absieht, das ein Singleton global nur eine Instanz hält, sehe ich dennoch nur wenige Unterschiede zwischen globalen Variablen, Singletons und Funktionen die eine statische Variable zurückliefert. Von den Grundprinzip hat man bei allen 3 Ansätzen ähnliche Anforderungen: Zugriff von mehreren Stellen auf einen bestimmten Kontent, der zur Laufzeit erhalten bleibt.
Nope und ich zitiere natürlich immer gern jene schicksalhafte Seite 127, die wohl besser niemals gedruckt worden wäre:
Gof schrieb:
Use the Singleton pattern when
- there must be exactly on instance of a class, and it must be accessible to clients from a well known access point.
- ...
asc schrieb:
dot schrieb:
asc schrieb:
z.B. für das halten einer globalen Konfiguration (mit schönen Fehlereffekten wegen Abhängigkeiten und Linkreihenfolgen die sich geändert hatten)...
Braunstein schrieb:
Wir verwenden gerade für solche globalen Konfigurationen auch Singletons.
Und mit genau welcher Begründung? Wieso genau muss um jeden Preis sichergestellt werden, dass die entsprechenden Typen hier und jetzt und für alle Zeit jemals nie mehr als einmal instanziert werden?
In unseren Programm gibt es bezogen auf eine Programminstanz genau _einen_ Benutzer, mit seinen Rechten und benutzerspezifischen Einstellungen; Bei der Programmkonfiguration sieht es ähnlich aus. Nenn mir hier den Grund warum man unbedingt mehrere Instanzen braucht.
Nenn mir einen Grund, warum man mehrere Instanzen hier explizit verbieten muss. Wenn du keinen hast, gibt es auch keinen Grund für ein Singleton. Genau da liegt der Knackpunkt: "Ich brauch nur eine Instanz" -> man macht nur eine Instanz, "Es ist eine wesentliche Eigenschaft des Typs, dass es um keinen Preis der Welt jemals mehr als genau eine Instanz davon gegeben darf" -> Singleton.
Ich kann dir nur wünschen, dass du den Tag nie erleben musst, an dem in dieser Anwendung plötzlich mehr als genau ein Benutzer mit seinen Rechten und benutzerspezifischen Einstellungen existieren soll.
asc schrieb:
Davon abgesehen gibt es auch Singletons die zwar eine Instanz eines bestimmten Typs halten, der Typ als solches aber seperat instanziert werden kann...
Nein, sowas gibt es per Definition nicht. Sobald ein Typ beliebig instanziert werden kann, ist es kein Singleton mehr, genau das macht doch das Singleton aus!? (hence the Name...)
asc schrieb:
Nummer 2 ist definitiv als Singleton [Meyer-Singleton] umgesetzt (basiert auf meinen Mist), da ich hier keinen Grund für mehrere Instanzen sehe.
Wie schon oben gesagt: Es gibt einen wesentlichen Unterschied zwischen "momentan keinen Grund für mehrere Instanzen sehen" und "einen Grund gegen mehrere Instanzen sehen" und Singleton ist potentiell nur in letzterem Fall angebracht.
-
dot schrieb:
Und mit genau welcher Begründung? Wieso genau muss um jeden Preis sichergestellt werden, dass die entsprechenden Typen hier und jetzt und für alle Zeit jemals nie mehr als einmal instanziert werden?
Nenn mir bitte eine Gegenbegründung, warum man für Daten die genau einmal im System existieren kein Singleton verwenden sollte. Es gibt hier ebenso keinen Zusatznutzen wenn ich eine Instanz über beispielsweise eine statische Variable in einer Funktion erzeuge und zurückgebe.
Ebenso...
dot schrieb:
asc schrieb:
Davon abgesehen gibt es auch Singletons die zwar eine Instanz eines bestimmten Typs halten, der Typ als solches aber seperat instanziert werden kann...
Nein, sowas gibt es per Definition nicht.
...gibt es mehr Farben als schwarz und weiß.
Vereinfacht, und unvollständig:
template<T> class Singleton { public: static T& GetInstance(); }Solche Konstrukte habe ich bereits gesehen (wenn auch nicht selbst im Einsatz).
dot schrieb:
Wie schon oben gesagt: Es gibt einen wesentlichen Unterschied zwischen "momentan keinen Grund für mehrere Instanzen sehen" und "einen Grund gegen mehrere Instanzen sehen" und Singleton ist potentiell nur in letzterem Fall angebracht.
Dann nenn mir einen Fall in dem es Sinn macht das an einer Programminstanz _gleichzeitig_ mehrere Benutzer angemeldet sein müssten (Macht für mich wenig Sinn). Oder warum man die allgemeinen (für alle gültigen) Programmeinstellungen mehrfach halten muss?
Ich will nicht sagen das Singletons ideal sind, aber ich sehe hier auch keinen Zusatznutzen für die Verwendung einer wie auch immer anders gearteten globalen Instanz (globale Variable / statische Variable die man über Funktion abfragt...).
-
asc schrieb:
dot schrieb:
Und mit genau welcher Begründung? Wieso genau muss um jeden Preis sichergestellt werden, dass die entsprechenden Typen hier und jetzt und für alle Zeit jemals nie mehr als einmal instanziert werden?
Nenn mir bitte eine Gegenbegründung, warum man für Daten die genau einmal im System existieren kein Singleton verwenden sollte.
Weil zumindest die Konstruktionsbeschränkung unnötig ist. Abgesehen davon, gelten natürlich sämtliche Nachteile von globalem Zustand allgemein, wie z.B.:
- Verschleierung von Abhängigkeiten
- Probleme mit Multithreading
- Unit Testing kompliziert bis praktisch unmöglich
- Probleme mit komplexen Abhängigkeiten und Destruktionsreihenfolge
asc schrieb:
Es gibt hier ebenso keinen Zusatznutzen wenn ich eine Instanz über beispielsweise eine statische Variable in einer Funktion erzeuge und zurückgebe.
Es geht ums Prinzip. Wenn es keinen Grund gibt, das Ding zu einem Singleton zu machen, dann macht man das Ding nicht zu einem Singleton.
asc schrieb:
dot schrieb:
asc schrieb:
Davon abgesehen gibt es auch Singletons die zwar eine Instanz eines bestimmten Typs halten, der Typ als solches aber seperat instanziert werden kann...
Nein, sowas gibt es per Definition nicht.
...gibt es mehr Farben als schwarz und weiß.
Vereinfacht, und unvollständig:
template<T> class Singleton { public: static T& GetInstance(); }Solche Konstrukte habe ich bereits gesehen (wenn auch nicht selbst im Einsatz).
Und weil derjenige, der es geschrieben hat, das Ding "Singleton" genannt hat, muss es deiner Meinung nach ein Singleton sein!? Sry, aber das da oben ist kein Singleton, da gibt's eigentlich nicht wirklich was zu diskutieren, wenn du mir nicht glaubst, dann konsultiere eben eine Quelle deines Vertrauens, z.B. das GoF Buch.
asc schrieb:
dot schrieb:
Wie schon oben gesagt: Es gibt einen wesentlichen Unterschied zwischen "momentan keinen Grund für mehrere Instanzen sehen" und "einen Grund gegen mehrere Instanzen sehen" und Singleton ist potentiell nur in letzterem Fall angebracht.
Dann nenn mir einen Fall in dem es Sinn macht das an einer Programminstanz _gleichzeitig_ mehrere Benutzer angemeldet sein müssten (Macht für mich wenig Sinn). Oder warum man die allgemeinen (für alle gültigen) Programmeinstellungen mehrfach halten muss?
Schonmal in letzter Zeit ein Betriebssystem verwendet? Mag sein, dass es in deiner Anwendung momentan keinen Sinn macht. Das ist imo eben trotzdem kein Grund, die Möglichkeit auszuschließen, wenn man nichtmal einen Nutzen davon trägt. Aber egal, von mir aus darfst du gerne weiter dran festhalten.

Edit: Cat hat es hier damals sehr schön auf den Punkt gebracht.
-
dot schrieb:
asc schrieb:
Nenn mir bitte eine Gegenbegründung, warum man für Daten die genau einmal im System existieren kein Singleton verwenden sollte.
Weil zumindest die Konstruktionsbeschränkung unnötig ist. Abgesehen davon, gelten natürlich sämtliche Nachteile von globalem Zustand allgemein, wie...
Das gilt aber auch für die zwei direkten Alternativen: Als globale Varialbe oder als Funktion mit Rückgabe einer statischer Variable.
Jedesmal wenn ich ein Recht in unserer Anwendung überprüfe (und das geschieht teilweise auf Datensatzebene - was gerade bei Listen zu sehr vielen Überprüfungen führen kann), kann ich nicht jedesmal die Daten neu einlesen (Dank verschiedenen Abhängigkeiten, Lizenzen etc. würde das jedesmal auch mehr als nur ein paar Abfragen bedeuten).
Welche Alternativen siehst du, wenn man nicht ständig neue Objekte erzeugen will? Die Nachteile dank globaler Datenhaltung sind mir bekannt - aber für die Alternativen habe ich die gleichen Nachteile gefunden... Nun?
-
asc schrieb:
Welche Alternativen siehst du, wenn man nicht ständig neue Objekte erzeugen will? Die Nachteile dank globaler Datenhaltung sind mir bekannt - aber für die Alternativen habe ich die gleichen Nachteile gefunden... Nun?
globale Datenhaltung hat nichts mit Singleton zu tun.
-
asc schrieb:
Jedesmal wenn ich ein Recht in unserer Anwendung überprüfe (und das geschieht teilweise auf Datensatzebene - was gerade bei Listen zu sehr vielen Überprüfungen führen kann), kann ich nicht jedesmal die Daten neu einlesen (Dank verschiedenen Abhängigkeiten, Lizenzen etc. würde das jedesmal auch mehr als nur ein paar Abfragen bedeuten).
Welche Alternativen siehst du, wenn man nicht ständig neue Objekte erzeugen will? Die Nachteile dank globaler Datenhaltung sind mir bekannt - aber für die Alternativen habe ich die gleichen Nachteile gefunden... Nun?
Ich fürchte, dass ich zu wenig Ahnung von der konkreten Anwendung hab, als dass ich da jetzt über Alternativen nachdenken könnte. Wieso genau müsstest du denn "ständig neue Objekte erzeugen"?
-
dot schrieb:
Nexus schrieb:
Andererseits sieht man oft den Fehler, dass jede Klasse, die nur einmal instanziiert wird, gleich zu einem Singleton gemacht wird.
Genau das ist der Punkt. Eine globale Variable ist eine Instanz eines Typs. Ein Singleton ist ein Typ, der nur einmal instanziert werden kann.
Auch wenn die übliche Implementierung eines Singleton in C++ einen globalen Zugriffspunkt auf diese eine Instanz impliziert, sind das imo immer noch zwei völlig unabhängige Konzepte, wie z.B. "Flugzeug" und "Urlaub" auch...Für mich macht die Unterscheidung überhaupt keinen Sinn.
Einzig dass das Singleton 0 bis 1 Instanzen zulässt, die globale Variable aber immer genau 1x existiert ist ein Unterschied. Der aber meist nicht interessiert - globale Variablen verwendet man auch oft genug um etwas zu bauen was erstmal initialisiert werden muss. Vom Konzept her ist das dann genau das gleiche.
Und vor allem: ich kann Code der mit lauter globalen Variablen arbeitet jederzeit in Code der ein Singleton verwendet überführen, und umgekehrt.
"Singleton" ist also bloss ein Wort mit dem man versucht etwas schön zu reden, was nicht schön ist. Da "globale Variable" stärker negativ belegt ist als "Singleton", funktioniert das auch oft.
-
asc schrieb:
Jedesmal wenn ich ein Recht in unserer Anwendung überprüfe (und das geschieht teilweise auf Datensatzebene - was gerade bei Listen zu sehr vielen Überprüfungen führen kann), kann ich nicht jedesmal die Daten neu einlesen (Dank verschiedenen Abhängigkeiten, Lizenzen etc. würde das jedesmal auch mehr als nur ein paar Abfragen bedeuten).
Hat dein Programm kein "Session" oder "Connection" Objekt wo man solche Daten reinstopfen könnte?
-
hustbaer schrieb:
Hat dein Programm kein "Session" oder "Connection" Objekt wo man solche Daten reinstopfen könnte?
Nein... Auch wenn der Code dafür noch recht gut ist, handelt es sich hier um ein "historisch" gewachsenes Projekt (Einzelne Codeteile sind inzwischen über 10 Jahre alt). Teilweise mit direkter Bindung von Oberfläche an DB-Controls.
Das einzige was über die gesamte Laufzeit existiert ist das VCL-Application-Objekt, und da kann ich nicht ohne weiteres igendetwas einfügen.
-
hustbaer schrieb:
"Singleton" ist also bloss ein Wort mit dem man versucht etwas schön zu reden, was nicht schön ist. Da "globale Variable" stärker negativ belegt ist als "Singleton", funktioniert das auch oft.
Wobei es ein Aspekt gibt die ich dennoch bei einem Singleton besser finde, als bei einer globalen Variable (gilt aber auch für Funktionen mit Referenzrückgabe einer statischer Variablen): Die Initialisierung erfolgt erst mit dem Zugriff - Probleme wegen geänderten Linkreihenfolgen sind daher geringer.
Nein, ich will Singletons nicht schön reden. Ich ziehe sie aber (in seltenen Fällen) dennoch in Betracht. Dies sind im wesentlichen aber auch die von mir genannten Fälle (z.B. Für den Zugriff auf die Einstellungen zum Programm und für die Daten des aktuell angemeldeten Benutzers).
-
Naja gut wenn das ein GUI Teil ist, und es kein Objekt gibt wo man die Daten sinnvoll reinstopfen könnte, und man mit vertretbarem Aufwand auch keines einführen kann, dann mach nen Singleton.
Eine schöne GetXYZ() Funktion die eine Referenz auf irgend eine Klasse zurückgibt. (Oder auch XYZ::GetInstance()).
Der Sinn der GetXYZ() Funktion ist hier hauptsächlich dass man die Stellen schnell anfindet wo zugegriffen wird -- auf die Art lässt es sich leichter refactoren wenn das mal nötig sein sollte.
Und der Sinn der Klasse ist hauptsächlich damit der Code übersichtlich bleibe. Ansammlungen von globalen Variablen und freien Zugriffsfunktionen entarten viel zu schnell - vor allem wenn mehr als ein Programmierer an einem Projekt arbeitet, oder der einzige Programmierer etwas zum Chaos neigt.
Konzeptionell bleibt es für mich das selbe, aber es wäre wohl wirklich angebracht ein Singleton zu verwenden - aus oben genannten Gründen.
-
asc schrieb:
hustbaer schrieb:
"Singleton" ist also bloss ein Wort mit dem man versucht etwas schön zu reden, was nicht schön ist. Da "globale Variable" stärker negativ belegt ist als "Singleton", funktioniert das auch oft.
Wobei es ein Aspekt gibt die ich dennoch bei einem Singleton besser finde, als bei einer globalen Variable (gilt aber auch für Funktionen mit Referenzrückgabe einer statischer Variablen): Die Initialisierung erfolgt erst mit dem Zugriff - Probleme wegen geänderten Linkreihenfolgen sind daher geringer.
Kannst du auch mit globalen Variablen haben.
Sagt ja keiner dass man die Zugriffe auf globale Variablen nicht hinter Getter-Funktionen verstecken kann. Und die verzögerte Initialisierung kann man dann in der Getter-Funktion machen.Genaugenommen kann man viele so kleine Änderungen machen, die alle nichts wesentliches ändern, bis am Ende dann was rauskommt was alle als Implementierung des Singleton Patterns bezeichnen würden. Daher meine ich ja auch dass es von Prinzip her das selbe ist.
Nein, ich will Singletons nicht schön reden. Ich ziehe sie aber (in seltenen Fällen) dennoch in Betracht. Dies sind im wesentlichen aber auch die von mir genannten Fälle (z.B. Für den Zugriff auf die Einstellungen zum Programm und für die Daten des aktuell angemeldeten Benutzers).
Jo, dagegen sag' ich ja gar nix.
Ich verstehe schon dass manchmal Dinge Sinn machen die eigentlich nicht das sind was man sich wünschen würde.
-
hustbaer schrieb:
Hat dein Programm kein "Session" oder "Connection" Objekt wo man solche Daten reinstopfen könnte?
So ein Session Objekt ist letztendlich doch auch bloß wieder eine, mehr oder minder gekapselte, globale Variable oder?
-
Braunstein schrieb:
So ein Session Objekt ist letztendlich doch auch bloß wieder eine, mehr oder minder gekapselte, globale Variable oder?
Im wesentlichen schon
