Ist es eine schlechte Methode, statische Variablen in Funktionen / Member-Funktionen zu deklarieren?

8
Kürzlich hat mir ein Kollege einen Code wie diesen gezeigt:

%Vor%

Er möchte überprüfen, ob SomeClass initialisiert ist, um ein Stück Code einmal pro Someclass -Instanz auszuführen, aber Tatsache ist, dass nur eine Instanz von SomeClass in der gesamten Lebensdauer des Programms existiert.

Seine Frage lautete über die statische Variable init , etwa wenn sie initialisiert wird. Ich habe geantwortet, dass die Initialisierung einmal erfolgt, so dass der Wert false beim ersten Aufruf und true der Rest seiner Lebensdauer ist. Nach dem Antworten habe ich hinzugefügt, dass solche Verwendung von statischen Variablen schlechte Praxis ist, aber ich konnte nicht erklären warum.

Die Gründe, die ich bisher gedacht habe, sind die folgenden:

  • Das Verhalten von static bool init in SomeClass::function kann mit einer nicht statischen Elementvariablen erreicht werden.
  • Andere Funktionen in SomeClass konnten den static bool init -Wert nicht überprüfen, da die Sichtbarkeit auf den void SomeClass::function() -Bereich beschränkt ist.
  • Die statischen Variablen sind nicht OOPish , weil sie einen globalen Zustand anstelle eines Objektstatus definieren.

Diese Gründe sehen schlecht aus, sind für mich nicht so konkret und nicht sehr konkret, deshalb frage ich nach weiteren Gründen, warum die Verwendung von statischen Variablen im Funktions- und Elementfunktionsraum eine schlechte Übung ist.

Danke!

    
Paula_plus_plus 06.03.2013, 16:31
quelle

4 Antworten

8

Dies ist sicherlich ein seltenes Vorkommnis, zumindest in guter Qualität Code, wegen der engen Fall, für den es angemessen ist. Was dies grundsätzlich tut, ist eine Just-in-Time-Initialisierung eines globalen Zustands (um einige globale Funktionalität zu liefern). Ein typisches Beispiel hierfür ist eine Zufallsgeneratorfunktion, die den Generator beim ersten Aufruf sät. Eine andere typische Verwendung davon ist eine Funktion, die die Instanz eines Singletons zurückgibt, die beim ersten Aufruf initialisiert wurde. Aber andere Anwendungsfälle sind selten.

Im Allgemeinen ist ein globaler Zustand nicht wünschenswert, und es wird bevorzugt, Objekte zu haben, die autarke Zustände enthalten (für Modularität usw.). Aber wenn Sie den globalen Status benötigen (und manchmal auch), müssen Sie es irgendwie implementieren. Wenn Sie einen nicht-trivialen globalen Status benötigen, sollten Sie wahrscheinlich eine Singleton-Klasse verwenden. Eine der bevorzugten Methoden zum Bereitstellen dieser anwendungsweiten Einzelinstanz ist eine Funktion, die einen Verweis auf eine initialisierte lokale statische Instanz bereitstellt beim ersten Anruf. Wenn der benötigte globale Zustand ein wenig trivialer ist, dann ist das Ausführen des Schemas mit dem lokalen statischen Bool-Flag sicherlich ein akzeptabler Weg, dies zu tun. Mit anderen Worten, ich sehe kein grundsätzliches Problem bei der Anwendung dieser Methode , aber ich würde natürlich ihre Motivationen (die einen globalen Zustand erfordern) hinterfragen, wenn sie mit einem solchen Code dargestellt werden.

Wie es bei globalen Daten immer der Fall ist, wird Multithreading einige Probleme mit einer vereinfachten Implementierung wie dieser verursachen. Naive Einführungen des globalen Staates werden nie von Natur aus threadsicher sein, und dieser Fall ist keine Ausnahme, man müsste Maßnahmen ergreifen, um dieses spezifische Problem anzugehen. Und das ist einer der Gründe, warum globale Staaten nicht wünschenswert sind.

  

Das Verhalten der statischen Bool-Init in SomeClass :: function konnte mit einer nicht-statischen Elementvariablen erreicht werden.

Wenn es eine Alternative gibt, um das gleiche Verhalten zu erreichen, dann müssen die beiden Alternativen an den technischen Problemen (wie Thread-Sicherheit) beurteilt werden. Aber in diesem Fall ist das erforderliche Verhalten fragwürdiger als die Implementierungsdetails, und die Existenz alternativer Implementierungen ändert das nicht.

Zweitens sehe ich nicht, wie man eine Just-in-Time-Initialisierung eines globalen Zustands durch irgendetwas ersetzen kann, das auf einem nicht statischen Datenelement (einem statischen -Datenelement, könnte sein). Und selbst wenn Sie können, wäre es verschwenderisch (pro Objekt Speicher für eine einmalige pro Programm-Ausführung Sache erfordern), und allein auf diesem Grund, würde es nicht eine bessere Alternative machen.

  

Andere Funktionen in SomeClass konnten den statischen Bool-Initialisierungswert nicht überprüfen, da die Sichtbarkeit auf den void SomeClass :: function () - Bereich beschränkt ist.

Ich würde das generell in die Spalte "Pro" setzen (wie in Pro / Con). Das ist eine gute Sache. Dies ist das Ausblenden oder Einkapseln von Informationen. Wenn du Dinge verstecken kannst, die anderen nicht wichtig sind, dann ist das großartig! Wenn es jedoch andere Funktionen gibt, die wissen müssen, dass der globale Status bereits initialisiert wurde oder nicht, benötigen Sie wahrscheinlich etwas mehr in der Art einer Singleton-Klasse.

  

Die statischen Variablen sind nicht OOPish, weil sie einen globalen Zustand anstelle eines Objektstatus definieren.

OOPish oder nicht, wen interessiert das? Aber ja, der globale Staat ist hier das Problem. Nicht so sehr die Verwendung einer lokalen statischen Variablen zur Implementierung ihrer Initialisierung. Globale Staaten, insbesondere veränderliche globale Staaten, sind im Allgemeinen schlecht und sollten niemals missbraucht werden. Sie behindern die Modularität (Module sind weniger autark, wenn sie auf globale Zustände angewiesen sind), sie führen Multithreading-Probleme ein, weil sie inhärent geteilte Daten sind, sie machen jede Funktion, die sie nicht-reentrant (nicht rein) benutzt, sie debuggen schwierig, etc ... die Liste geht weiter. Die meisten dieser Probleme hängen jedoch nicht davon ab, wie Sie sie implementieren. Auf der anderen Seite ist die Verwendung einer lokalen statischen Variable ein guter Weg, um das Statische-Initialisierungs-Ordnung-Fiasko zu lösen, daher sind sie aus diesem Grund gut, ein Problem, um das man sich bei der Einführung eines (gut begründeten) globalen Zustands weniger Sorgen machen muss in deinen Code.

    
Mikael Persson 06.03.2013, 17:37
quelle
4

Denken Sie an Multithreading. Diese Art von Code ist problematisch, wenn function() gleichzeitig von mehreren Threads aufgerufen werden kann. Ohne Sperren sind Sie offen für die Rennbedingungen. Mit Sperren kann Nebenläufigkeit für keinen wirklichen Gewinn leiden.

    
NPE 06.03.2013 16:32
quelle
2

Der globale Staat ist wahrscheinlich das schlimmste Problem hier. Andere Funktionen müssen sich nicht darum kümmern, also ist das kein Problem. Die Tatsache, dass es ohne static variable erreicht werden kann, bedeutet im Wesentlichen, dass Sie eine Art Singleton gemacht haben. Das bringt natürlich alle Probleme mit sich, die Singleton hat, wie zum Beispiel für Multithread-Umgebungen völlig ungeeignet.

    
Bartek Banachewicz 06.03.2013 16:33
quelle
2

Zusätzlich zu dem, was andere gesagt haben, können Sie nicht mehrere Objekte dieser Klasse gleichzeitig haben oder sich zumindest nicht wie erwartet verhalten. Die erste Instanz würde die statische Variable setzen und die Initialisierung durchführen. Diejenigen, die später erstellt werden, haben jedoch keine eigene Version von init , sondern teilen sie mit allen anderen Instanzen. Da die erste Instanz es auf "true" setzt, werden alle folgenden keine Initialisierung durchführen, was höchstwahrscheinlich nicht das ist, was Sie wollen.

    
ahans 06.03.2013 16:44
quelle

Tags und Links