Globale Variablen --> niemals ?
Globale Variablen --> niemals ?
Hallo,
Ich arbeite unter Windows7 mit c++ (meist) und habe gelernt, dass es verpönt ist, globale Variablen zu verwenden.
Macht ja auch Sinn, da man mit Klassen wiederverwendbaren Code bauen will und da passen globale Variablen schlecht rein.
(Macht meinen Code gerade schlecht leserlich nach 10 Jahren.)
Dennoch habe ich das Gefühl, dass es manchmal nicht ohne geht, ohne übermässigen Spagat zu üben.
Z.B.
Ich habe mehrere Klassen, die mit dem DirectX Device hantieren müssen, welches ich nur einmal in einer Klasse erzeuge.
Oder ich habe eine Debug- bzw. Protokoll- Klasse, die natürlich auch nur einmal erzeugt wird, und alle Klassen sollen darauf zugreifen.
Mein Hauptprogramm fühlt sich nicht wie eine Klasse an --> "int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprevinst,.... .... ...."
Die Klassen werden vom Hauptprogramm in WinMain erzeugt(die meissten) und denen gebe ich die hinst/hwnd eigentlich nicht mit, damit diese dann wieder eine Nachfrage an das Hauptprogramm tätigen können, da dies unter anderem sehr mühsam ist. :D
Oder ist das genau der Punkt ?
Klasse erzeugen --> mit hinst des Erzeugers initialisieren --> Serviceroutionen einrichten und hier nutzen.
Das hat ja ein wildes Service-hin und her zur Folge.
Ist das wirklich nötig ?
Ich habe in meinen alten Projekten aktuell eine globale Struktur eingerichtet, wo die wichtigsten Klassen und Fenster(hwnd) z.B. gespeichert sind und werde das nicht mehr umbauen.
Aber mein neues Projekt sollte dann halt "besser" werden, wenn globale Variablen ein absolutes NoGo sind.
Wie macht ihr das ?
Haltet ihr Euch strikt an die No-global Regel oder macht ihr Ausnahmen und wann ?
Grüsse
Ich arbeite unter Windows7 mit c++ (meist) und habe gelernt, dass es verpönt ist, globale Variablen zu verwenden.
Macht ja auch Sinn, da man mit Klassen wiederverwendbaren Code bauen will und da passen globale Variablen schlecht rein.
(Macht meinen Code gerade schlecht leserlich nach 10 Jahren.)
Dennoch habe ich das Gefühl, dass es manchmal nicht ohne geht, ohne übermässigen Spagat zu üben.
Z.B.
Ich habe mehrere Klassen, die mit dem DirectX Device hantieren müssen, welches ich nur einmal in einer Klasse erzeuge.
Oder ich habe eine Debug- bzw. Protokoll- Klasse, die natürlich auch nur einmal erzeugt wird, und alle Klassen sollen darauf zugreifen.
Mein Hauptprogramm fühlt sich nicht wie eine Klasse an --> "int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprevinst,.... .... ...."
Die Klassen werden vom Hauptprogramm in WinMain erzeugt(die meissten) und denen gebe ich die hinst/hwnd eigentlich nicht mit, damit diese dann wieder eine Nachfrage an das Hauptprogramm tätigen können, da dies unter anderem sehr mühsam ist. :D
Oder ist das genau der Punkt ?
Klasse erzeugen --> mit hinst des Erzeugers initialisieren --> Serviceroutionen einrichten und hier nutzen.
Das hat ja ein wildes Service-hin und her zur Folge.
Ist das wirklich nötig ?
Ich habe in meinen alten Projekten aktuell eine globale Struktur eingerichtet, wo die wichtigsten Klassen und Fenster(hwnd) z.B. gespeichert sind und werde das nicht mehr umbauen.
Aber mein neues Projekt sollte dann halt "besser" werden, wenn globale Variablen ein absolutes NoGo sind.
Wie macht ihr das ?
Haltet ihr Euch strikt an die No-global Regel oder macht ihr Ausnahmen und wann ?
Grüsse
- Schrompf
- Moderator
- Beiträge: 5077
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Globale Variablen --> niemals ?
Ich nehme auch globale Klassen, wenn nötig. Der Logger ist so eine. Display und DrawContext sind auch globale Klassen, auch wenn es von DrawContext noch weitere lokale Instanzen geben kann. Leider sind die Verlockungen dann immer nah und greifbar, doch schnell in eine globale Klasse reinzugreifen und sich von dort irgendeinen kleinen Informationsfetzen zu besorgen. Und wenn man dem nicht widersteht, zieht sich der globale Zugriff wie Metastasen durch erstaunlich viele Teile des Programms. Was man aber erst so richtig wahrnimmt, wenn man Unittests dafür schreiben will.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Re: Globale Variablen --> niemals ?
Sowas wie Logger und WindowManagement kann man gut in statische Klassen oder Singletons packen, dann hat man auch globalen Zugriff, kann diesen aber besser kapseln / testen / ...
Es kommt auch auf die Art der Entwicklung an, globale Variablen sind in der prozedualen Anwendungsentwicklung nützlich (zumindest waren sie das für mich?).
Vielleicht sollte man sich nochmal überlegen warum globale Variablen verpönt sind. Dies hat ja damit zu tun dass sie eben von überall aus geändert werden können und somit manche Abläufe nicht sichergestellt werden können da du z.B. niemals weisst in welchem Status sich die Variable gerade befindet.
Es kommt auch auf die Art der Entwicklung an, globale Variablen sind in der prozedualen Anwendungsentwicklung nützlich (zumindest waren sie das für mich?).
Vielleicht sollte man sich nochmal überlegen warum globale Variablen verpönt sind. Dies hat ja damit zu tun dass sie eben von überall aus geändert werden können und somit manche Abläufe nicht sichergestellt werden können da du z.B. niemals weisst in welchem Status sich die Variable gerade befindet.
-
- Establishment
- Beiträge: 426
- Registriert: 23.01.2013, 15:55
Re: Globale Variablen --> niemals ?
Ich denke, dass die zentrale ganz wichtige Sache, warum globale Variablen tatsächlich schlecht sind, wurde bisher noch gar nicht richtig auf den Punkt gebracht:
Die Abhänigkeiten. Wenn du eine globale Variable verwendest, kann diese von überall zugegriffen werden. Das verschleiert die Zusammenhänge in deinem Programm erheblich, weil in dem Interface aller Funktionen/Klassen die diese globale Variable verwenden, diese nicht auftaucht. Jede Funktion kann jeder Zeit im Hintergrund auf deine Variable zugreifen und den Zustand ändern und es ist nicht klar ersichtlich woher der aktuelle Zustand kommt, weil er einfach immer im Hintergrund da ist ("Zombie"). Globale Variablen verschlechtern so erheblich die Selbstdokumentation deines Codes. Extrembeispiel: errno Die fehlende Zugehörigkeit ist auch ein Problem für die Thread-Sicherheit.
Singletons laufen im Prinzip auf das selbe wie globale Variablen heraus, sind jedoch zusätzlich auch noch deutlich weniger flexibel, weil es garantiert nur eine Instanz geben kann. Eine globale Variable scheint mir eigentlich ausnahmelos die bessere Option.
Ausgenommen von den "bösen globalen Variablen Prinzip" sind übrigens solche die konstant sind (weil kein unbekannter State im Hintergrund). Wenn globale Variablen "privat" sind und dessen State keine Auswirkungen auf das öffentliche Interface haben, sind sie auch eher in Ordnung, wobei man hier wieder auf Thread-Sicherheit zwischen eigentlich unabhänigen Instanzen achten muss. (zb. ein globaler Cache im Hintergrund wäre ein möglicher Anwendungsfall)
Wie Schrompf schon richtig gesagt wird, wirkt es häufig verlockend, einfach eine globale Variable zu verwenden. Es wirkt auf den ersten Blick auch flexibel, weil man diese dann überall einfach verwenden kann, ohne das man später eventuell viele Parameter anpassen muss um die Instanz noch mit zu übergeben. Hier liegt jedoch ein Denkfehler vor, weil die Abhänigkeit natürlich nicht verschwindet, bloß weil man sie nicht als Parameter übergibt. Die Zeit die hier scheinbar gespart wurde, weil man sich scheinbar keine Gedanken darüber machen muss, wer das Objekt bekommt, holt einen über die Zeit wieder ein wenn nicht mehr intuitiv klar ist, wer etwas an dem Objekt ändert. Tatsächlich benötigen alle Funktionen einfach einen bestimmten Kontext und State um zu funktionieren. Mit einer globalen Variable ist der nicht mehr erkennbar.
Unter all den genannten Beispielen halte ich eigentlich nur den "Logger" für einen in meinen Augen sinnvollen Fall für eine globale Variable. Ein Logger besitzt wenig State und sollte in der Regel Exception Safe und Thread-sicher und einfach immer funktionieren. (so ähnlich wie "printf") Außerdem ist es tatsächlich wünschenswert, wenn einfach jede einzelne Funktion im Programm eine Log-Meldung abgegeben kann, ohne dass man zu jeder einzelnen Funktion im Programm das Objekt übergibt. Ein Display oder DrawContext scheint mir dagegen kaum geeignet. Ich halte es auch für eine gruselige Vorstellung, wenn jede Funktion in meinen Programm etwas an meinen "DrawContext" verstellen oder von dessen State abhänig sein kann. Das ist dann nicht mehr offensichtlich. Außerdem gibt es nicht immer einen "DrawContext". Ich sehe da wenig Schwierigkeiten darin, einfach den paar "Render"-Funktionen in einem Programm das "DrawContext"-Objekt einfach als Parameter zu übergeben.
Globale bzw. statische Klassen gibt es in C++ übrigens nicht.
Die Abhänigkeiten. Wenn du eine globale Variable verwendest, kann diese von überall zugegriffen werden. Das verschleiert die Zusammenhänge in deinem Programm erheblich, weil in dem Interface aller Funktionen/Klassen die diese globale Variable verwenden, diese nicht auftaucht. Jede Funktion kann jeder Zeit im Hintergrund auf deine Variable zugreifen und den Zustand ändern und es ist nicht klar ersichtlich woher der aktuelle Zustand kommt, weil er einfach immer im Hintergrund da ist ("Zombie"). Globale Variablen verschlechtern so erheblich die Selbstdokumentation deines Codes. Extrembeispiel: errno Die fehlende Zugehörigkeit ist auch ein Problem für die Thread-Sicherheit.
Singletons laufen im Prinzip auf das selbe wie globale Variablen heraus, sind jedoch zusätzlich auch noch deutlich weniger flexibel, weil es garantiert nur eine Instanz geben kann. Eine globale Variable scheint mir eigentlich ausnahmelos die bessere Option.
Ausgenommen von den "bösen globalen Variablen Prinzip" sind übrigens solche die konstant sind (weil kein unbekannter State im Hintergrund). Wenn globale Variablen "privat" sind und dessen State keine Auswirkungen auf das öffentliche Interface haben, sind sie auch eher in Ordnung, wobei man hier wieder auf Thread-Sicherheit zwischen eigentlich unabhänigen Instanzen achten muss. (zb. ein globaler Cache im Hintergrund wäre ein möglicher Anwendungsfall)
Wie Schrompf schon richtig gesagt wird, wirkt es häufig verlockend, einfach eine globale Variable zu verwenden. Es wirkt auf den ersten Blick auch flexibel, weil man diese dann überall einfach verwenden kann, ohne das man später eventuell viele Parameter anpassen muss um die Instanz noch mit zu übergeben. Hier liegt jedoch ein Denkfehler vor, weil die Abhänigkeit natürlich nicht verschwindet, bloß weil man sie nicht als Parameter übergibt. Die Zeit die hier scheinbar gespart wurde, weil man sich scheinbar keine Gedanken darüber machen muss, wer das Objekt bekommt, holt einen über die Zeit wieder ein wenn nicht mehr intuitiv klar ist, wer etwas an dem Objekt ändert. Tatsächlich benötigen alle Funktionen einfach einen bestimmten Kontext und State um zu funktionieren. Mit einer globalen Variable ist der nicht mehr erkennbar.
Unter all den genannten Beispielen halte ich eigentlich nur den "Logger" für einen in meinen Augen sinnvollen Fall für eine globale Variable. Ein Logger besitzt wenig State und sollte in der Regel Exception Safe und Thread-sicher und einfach immer funktionieren. (so ähnlich wie "printf") Außerdem ist es tatsächlich wünschenswert, wenn einfach jede einzelne Funktion im Programm eine Log-Meldung abgegeben kann, ohne dass man zu jeder einzelnen Funktion im Programm das Objekt übergibt. Ein Display oder DrawContext scheint mir dagegen kaum geeignet. Ich halte es auch für eine gruselige Vorstellung, wenn jede Funktion in meinen Programm etwas an meinen "DrawContext" verstellen oder von dessen State abhänig sein kann. Das ist dann nicht mehr offensichtlich. Außerdem gibt es nicht immer einen "DrawContext". Ich sehe da wenig Schwierigkeiten darin, einfach den paar "Render"-Funktionen in einem Programm das "DrawContext"-Objekt einfach als Parameter zu übergeben.
Globale bzw. statische Klassen gibt es in C++ übrigens nicht.
Re: Globale Variablen --> niemals ?
Danke, das ist ausführlicher als mein halber Absatz und absolut korrekt :-)Ich denke, dass die zentrale ganz wichtige Sache, warum globale Variablen tatsächlich schlecht sind, wurde bisher noch gar nicht richtig auf den Punkt gebracht:
Die Abhänigkeiten. Wenn du eine globale Variable verwendest, kann diese von überall zugegriffen werden. Das verschleiert die Zusammenhänge in deinem Programm erheblich, weil in dem Interface aller Funktionen/Klassen die diese globale Variable verwenden, diese nicht auftaucht. Jede Funktion kann jeder Zeit im Hintergrund auf deine Variable zugreifen und den Zustand ändern und es ist nicht klar ersichtlich woher der aktuelle Zustand kommt, weil er einfach immer im Hintergrund da ist ("Zombie"). Globale Variablen verschlechtern so erheblich die Selbstdokumentation deines Codes. Extrembeispiel: errno Die fehlende Zugehörigkeit ist auch ein Problem für die Thread-Sicherheit.
Von einer globalen Variablen gibt es in dem Sinne ja auch nur eine Instanz, oder liege ich hier falsch? Ein Singleton kann u.U. mehr Möglichkeiten geben wie z.B. (abhängige) Methoden, etc.Singletons laufen im Prinzip auf das selbe wie globale Variablen heraus, sind jedoch zusätzlich auch noch deutlich weniger flexibel, weil es garantiert nur eine Instanz geben kann. Eine globale Variable scheint mir eigentlich ausnahmelos die bessere Option.
Hängt auch alles vom Konzept bzw. der "Architektur" ab.
-
- Establishment
- Beiträge: 426
- Registriert: 23.01.2013, 15:55
Re: Globale Variablen --> niemals ?
Eine globale Variable beinhaltet eine Instanz schließt aber nicht die Möglichkeit weiterer Instanzen aus. Bei einem Singleton gibt nur eine Instanz und die Möglichkeit weiterer Instanzen wird mithilfe eines "private"-Konstruktors absichtlich verhindert.
Code: Alles auswählen
//MyGreatLogClass.h
class MyGreatLogClass { ... };
MyGreatLogClass DefaultLog;
//Somewhere.cpp
void Somewhere()
{
MyGreatLogClass ServerLog; //Es kann eine weitere Log-Instanz erstellt werden. Bei einem Singleton wäre das nicht möglich.
}
Re: Globale Variablen --> niemals ?
Also, ich schliesse nun aus den Antworten, dass globale Variablen natürlich zu vermeiden sind, aufgrund ihrer negativen Eigenschaften.
Wenn man aber weis was man tut,
ich verwende also ausschliesslich Pointer auf eine Klasse(Logger und D3D-Interface/Device z.B.), weil es einfach bequemer und u.U. schneller ist.
Dies sind dann "Variablen", die am Anfang initialisiert werden und am Ende zerstört werden und dazwischen nicht verändert werden.
Ausserdem versuche ich die Menge der Variablen so gering wie Möglich zu halten. Aktuell sind es etwa 10 und alles Zeiger auf Klassen oder hwnd und zwei Strings zum initialisieren von Fenstern.
So wie ich Euch verstanden habe, wäre dies also noch vertretbar.
Ich wäre aber nicht auf die Idee gekommen, eine echte Variable global zu machen, deren Wert sich ständig ändert.
Die jeweilige Überprüfung auf Gültigkeit(NULL) wird zwar dennoch durchgeführt, aber ist eigentlich nicht nötig, da beim Erzeugen auf Gültigkeit geprüft wird.
Wenn ich das so richtig verstanden habe, dann danke ich schon mal allen beteiligten dafür, dass sie mein Gewissen etwas beruhigt haben. :lol:
Grüsse.
Wenn man aber weis was man tut,
ich verwende also ausschliesslich Pointer auf eine Klasse(Logger und D3D-Interface/Device z.B.), weil es einfach bequemer und u.U. schneller ist.
Dies sind dann "Variablen", die am Anfang initialisiert werden und am Ende zerstört werden und dazwischen nicht verändert werden.
Ausserdem versuche ich die Menge der Variablen so gering wie Möglich zu halten. Aktuell sind es etwa 10 und alles Zeiger auf Klassen oder hwnd und zwei Strings zum initialisieren von Fenstern.
So wie ich Euch verstanden habe, wäre dies also noch vertretbar.
Ich wäre aber nicht auf die Idee gekommen, eine echte Variable global zu machen, deren Wert sich ständig ändert.
Die jeweilige Überprüfung auf Gültigkeit(NULL) wird zwar dennoch durchgeführt, aber ist eigentlich nicht nötig, da beim Erzeugen auf Gültigkeit geprüft wird.
Wenn ich das so richtig verstanden habe, dann danke ich schon mal allen beteiligten dafür, dass sie mein Gewissen etwas beruhigt haben. :lol:
Grüsse.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Globale Variablen --> niemals ?
Nach globalen Variablen generell sollte man auch noch auf die sprachspezifischen Probleme eingehen. So bedeuten globale Variablen in C++
- undefinierte Initialisierungsreihenfolge („Ist mein Speicher-Manager *wirklich* schon initialisiert, wenn ich das erste Mal allokiere?“)
- Namenskollisionen (multiply defined symbol _fuckyour3rdpartylib)
- Duplikate, falls man die Variable im Header deklariert („Ich hab’ das doch gerade hier rein geschrieben, wieso ist das jetzt wieder weg?!“)
- Code Bloat (mov rbx, 0x8000000012345678 statt mov rbx, rax+8)