Wie wichtig ist es, eine Variable zu initialisieren?

9

Wie wichtig ist es, Variablen zu initialisieren?

Vermeidet eine ordnungsgemäße Initialisierung Speicherlecks oder hat sie Leistungsvorteile?

Vivek
quelle
14
Das hängt von der Sprache ab. In einigen Sprachen ist es ziemlich wichtig, Fehler zu vermeiden, in anderen Fällen ist es nur eine gute Sache, die Lesbarkeit zu verbessern.
Telastyn
Vielen Dank an Telastyn für Ihre Eingabe. Können Sie einen Fall nennen, in dem es je nach Sprache wichtig wird?
Vivek
4
C ++ ist hier berüchtigt. Beim Debuggen werden lokale Variablen nullvon den gängigen Compilern auf 0 (oder ) initialisiert , sind jedoch beim Kompilieren für die Veröffentlichung zufälliger Müll. (obwohl mein C ++ Wissen von vor ~ 10 Jahren ist, können sich die Dinge geändert haben)
Telastyn
Es ist ein Fall von einmal verbrannt, zweimal schüchtern. Da ich Fehler gesehen habe / hatte, die durch nicht initialisierte Variablen, insbesondere Zeiger, verursacht wurden, ist dies zur Gewohnheit geworden. Für die Leistung ist es normalerweise irrelevant. Bei Speicherlecks kein wirkliches Problem.
Mike Dunlavey
1
@ Telastyn es ist schlimmer als das. Undefiniertes Verhalten ist nicht auf den Müllzustand beschränkt, es kann alles passieren. Der Compiler kann davon ausgehen, dass Pfade, die nicht initialisierte Variablen lesen, nicht erreichbar sind, und dabei "nicht verwandte" Effekte eliminieren.
Caleth

Antworten:

7

Nicht initialisierte Variablen machen ein Programm nicht deterministisch. Jedes Mal, wenn das Programm ausgeführt wird, kann es sich anders verhalten. Unabhängige Änderungen der Betriebsumgebung, der Tageszeit, der Mondphase und deren Permutationen beeinflussen, wie und wann sich diese Dämonen manifestieren. Das Programm kann eine Million Mal ausgeführt werden, bevor der Fehler auftritt, sie können es jedes Mal tun oder eine weitere Million ausführen. Viele Probleme werden auf "Pannen" zurückgeführt und ignoriert oder Fehlerberichte von Kunden, die als "nicht reproduzierbar" geschlossen wurden. Wie oft haben Sie einen Computer neu gestartet, um ein Problem zu beheben? Wie oft haben Sie zu einem Kunden gesagt: "Noch nie gesehen, lassen Sie es mich wissen, wenn Sie es wieder sehen" - in der Hoffnung, dass sie es nicht tun!

Da die Reproduktion eines Defekts in der Testumgebung nahezu unmöglich sein kann, ist es nahezu unmöglich, ihn zu finden und zu beheben.

Es kann Jahre dauern, bis der Fehler auftritt. Dies gilt häufig für Code, der als zuverlässig und stabil angesehen wird. Es wird vermutet, dass der Fehler in neuerem Code vorliegt - das Aufspüren kann erheblich länger dauern. Eine Änderung des Compilers, ein Compilerwechsel oder sogar das Hinzufügen einer Codezeile können das Verhalten ändern.

Das Initialisieren von Variablen hat einen enormen Leistungsvorteil, nicht nur, weil ein Programm, das korrekt funktioniert, unendlich schneller ist als eines, das nicht funktioniert, sondern die Entwickler weniger Zeit damit verbringen, Fehler zu finden und zu beheben, die nicht vorhanden sein sollten, und mehr Zeit damit, "echte" Arbeit zu leisten.

Der andere wesentliche Vorteil der Initialisierung von Variablen besteht darin, dass der ursprüngliche Autor des Codes entscheiden muss, auf welche Weise sie initialisiert werden sollen. Dies ist nicht immer eine triviale Übung und kann, wenn sie nicht trivial ist, ein Hinweis auf ein schlechtes Design sein.

Speicherlecks sind ein anderes Problem, aber eine ordnungsgemäße Initialisierung kann nicht nur dazu beitragen, sie zu verhindern, sondern auch dazu, sie zu erkennen und die Quelle zu finden - sie ist stark sprachabhängig und das ist wirklich eine separate Frage, die weiter untersucht werden sollte, als ich geben kann in dieser Antwort.

Bearbeiten: In einigen Sprachen (z. B. C #) ist es nicht möglich, nicht initialisierte Variablen zu verwenden, da das Programm nicht kompiliert oder bei Ausführung einen Fehler meldet, wenn dies erledigt ist. Viele Sprachen mit diesen Merkmalen verfügen jedoch über Schnittstellen zu möglicherweise unsicherem Code. Daher muss bei der Verwendung solcher Schnittstellen darauf geachtet werden, keine nicht initialisierten Variablen einzuführen.

mattnz
quelle
6
Viele Programmiersprachen setzen ihre Variablen automatisch auf einen vordefinierten Wert, sodass vieles, was Sie hier sagen, nicht auf diese Sprachen anwendbar ist.
Robert Harvey
2
Um noch einmal zu wiederholen, was @RobertHarvey gesagt hat, ist nichts davon auf C # anwendbar. Das Initialisieren Ihrer Variablen beim Deklarieren bietet keinen Leistungsvorteil, und es ist unmöglich, eine nicht initialisierte Variable zu verwenden. Sie können also keine nicht reproduzierbaren Fehler dafür verantwortlich machen. (Es ist möglich, ein nicht initialisiertes Klassenfeld zu verwenden, aber es wird auf einen Standardwert gesetzt und generiert in diesem Fall eine Warnung)
Bobson
4
@mattnz - Der Punkt ist, dass für Sprachen, die sich wie C # (oder Java) verhalten, einige dieser Ratschläge irreführend oder völlig falsch sind. Als Sprache Agnostiker Frage, sollte es eine sprachunabhängig Antwort haben, was bedeutet , Adressieren Sprachen , die nicht sicher als auch Griff initialisierten Variablen wie diejenigen , die nicht tun.
Bobson
1
Ich möchte auch hinzufügen, dass nicht initialisierte Variablenprobleme nicht schwer zu finden sind, da jeder halbwegs anständige Compiler / statische Analysator vor ihnen warnt
jk.
1
Für Java (und vermutlich C #) ist eine vorzeitige Initialisierung von Einheimischen nicht erforderlich und führt möglicherweise zu weiteren Fehlern. Wenn Sie beispielsweise eine Variable vor dem Zuweisen auf Null setzen, wird die Fähigkeit des Compilers, Ihnen mitzuteilen, dass einer der Pfade durch den Code möglicherweise nicht dazu führt, dass die Variable zugewiesen wird, beeinträchtigt.
JimmyJames
7

Das Initialisieren einer Variablen, wie Telastyn hervorhob, kann Fehler verhindern. Wenn es sich bei der Variablen um einen Referenztyp handelt, kann durch deren Initialisierung später null Referenzfehler vermieden werden.

Eine Variable eines beliebigen Typs mit einem Standardwert ungleich Null belegt etwas Speicher, um den Standardwert zu speichern.

Kevin
quelle
6

Der Versuch, eine nicht initialisierte Variable zu verwenden, ist immer ein Fehler. Daher ist es sinnvoll, die Wahrscheinlichkeit des Auftretens dieses Fehlers zu minimieren.

Der wahrscheinlich häufigste Ansatz für Programmiersprachen zur Minderung des Problems ist die automatische Initialisierung auf einen Standardwert. Wenn Sie also vergessen, eine Variable zu initialisieren, ist dies eher so etwas als so 0etwas 0x16615c4b.

Dies behebt einen großen Prozentsatz von Fehlern, wenn Sie ohnehin eine auf Null initialisierte Variable benötigen. Die Verwendung einer Variablen, die mit einem falschen Wert initialisiert wurde, ist jedoch genauso schlecht wie die Verwendung einer Variablen, die überhaupt nicht initialisiert wurde. In der Tat kann es manchmal sogar noch schlimmer sein, weil der Fehler subtiler und schwieriger zu erkennen sein kann.

Funktionale Programmiersprachen lösen dieses Problem, indem sie nicht nur nicht initialisierte Werte, sondern auch die Neuzuweisung insgesamt nicht zulassen. Das beseitigt das Problem und stellt sich als nicht so schwerwiegende Einschränkung heraus, wie Sie vielleicht denken. Selbst in nicht funktionierenden Sprachen ist Ihr Code viel robuster, wenn Sie darauf warten, eine Variable zu deklarieren, bis Sie einen korrekten Wert zum Initialisieren haben.

Was die Leistung angeht, ist sie wahrscheinlich vernachlässigbar. Im schlimmsten Fall haben Sie bei nicht initialisierten Variablen eine zusätzliche Zuweisung und binden etwas Speicher länger als nötig. Gute Compiler können in vielen Fällen die Unterschiede optimieren.

Speicherlecks sind völlig unabhängig, obwohl ordnungsgemäß initialisierte Variablen in der Regel für einen kürzeren Zeitraum in Reichweite sind und daher für einen Programmierer möglicherweise etwas weniger wahrscheinlich sind, dass sie versehentlich auslaufen.

Karl Bielefeldt
quelle
Immer? Sie meinen, dass "immer" wie in "Wie eine feste Valgrind-Nachricht OpenSSL neben nutzlos gemacht hat" marc.info/?t=114651088900003&r=1&w=2 ? Oder meinst du den anderen, den "fast immer" einen?
JensG
1
Ich kann mir drei Sprachen vorstellen, die nicht initialisierte Variablen ohne Fehler zulassen, von denen eine solche für sprachliche Zwecke verwendet.
DougM
Ich würde mich für die Einzelheiten interessieren. Ich würde in diesen Fällen vermuten, dass die Variablen nicht wirklich nicht initialisiert sind, sondern auf eine andere Weise als direkt vom Programmierer an der Deklarationsstelle initialisiert werden. Oder sie werden auf indirekte Weise zugewiesen, bevor sie dereferenziert werden.
Karl Bielefeldt
5

Initialisieren bedeutet, dass der Anfangswert wichtig ist. Wenn der Anfangswert wichtig ist, müssen Sie natürlich sicherstellen, dass er initialisiert ist. Wenn es keine Rolle spielt, bedeutet dies, dass es später initialisiert wird.

Unnötige Initialisierung führt zu verschwendeten CPU-Zyklen. Während diese verschwendeten Zyklen in bestimmten Programmen möglicherweise keine Rolle spielen, ist in anderen Programmen jeder einzelne Zyklus wichtig, da die Geschwindigkeit von größter Bedeutung ist. Daher ist es sehr wichtig zu verstehen, was die eigenen Leistungsziele sind und ob Variablen initialisiert werden müssen oder nicht.

Speicherlecks sind ein völlig anderes Problem, bei dem normalerweise eine Speicherzuweisungsfunktion zum Ausgeben und späteren Recyceln von Speicherblöcken erforderlich ist. Denken Sie an ein Postamt. Sie gehen und fragen nach einem Briefkasten. Sie geben dir eins. Sie fragen nach einem anderen. Sie geben dir noch einen. Die Regel lautet: Wenn Sie mit der Verwendung eines Postfachs fertig sind, müssen Sie es zurückgeben. Wenn Sie vergessen, es zurückzugeben, denken sie immer noch, dass Sie es haben, und die Box kann von niemand anderem wiederverwendet werden. Es ist also ein Teil des Speichers gebunden und wird nicht verwendet, und dies wird als Speicherverlust bezeichnet. Wenn Sie irgendwann immer wieder nach Boxen fragen, wird Ihnen der Speicher ausgehen. Ich habe das zu stark vereinfacht, aber das ist die Grundidee.

Elliptische Ansicht
quelle
-1 Sie definieren neu, was Initialisierung in diesem Zusammenhang bedeutet.
Pieter B
@Pieter B, ich verstehe deinen Kommentar nicht. Wenn Sie so wollen, sagen Sie bitte, wie es mir geht, "definieren Sie neu, was Initialisierung in diesem Zusammenhang bedeutet". Vielen Dank
Ellipsentrainer
Lesen Sie Ihren eigenen Satz, es ist eine Zirkelschlussfolgerung: "Initialisieren bedeutet, dass der Anfangswert wichtig ist. Wenn der Anfangswert wichtig ist, dann müssen Sie natürlich sicherstellen, dass er initialisiert wird. Wenn es keine Rolle spielt, bedeutet dies, dass er erhalten wird später initialisiert. "
Pieter B
@Pieter B, Einige Leute initialisieren in der Regel und nicht aus programmatischen Gründen, dh sie initialisieren, ob der Anfangswert wichtig ist oder nicht. Ist das nicht das Herzstück von OQ: Wie wichtig ist es, eine Variable zu initialisieren? Wie auch immer, Sie wurden hier abgewählt.
Elliptische Ansicht
2

Wie andere sagten, kommt es auf die Sprache an. Aber ich werde meine Java- (und Effective Java-) Ideen zum Initialisieren von Variablen demonstrieren. Diese sollten für viele andere höhere Sprachen verwendbar sein.

Konstanten und Klassenvariablen

Klassenvariablen - staticin Java mit markiert - sind wie Konstanten. Diese Variablen sollten normalerweise endgültig sein und direkt nach der Definition mithilfe =oder innerhalb eines Klasseninitialisiererblocks initialisiert werden static { // initialize here }.

Felder

Wie in vielen höheren Ebenen und Skriptsprachen wird den Feldern automatisch ein Standardwert zugewiesen. Für Zahlen und chardies ist der Nullwert. Für Strings und andere Objekte wird es sein null. Jetzt nullist gefährlich und sollte sparsam eingesetzt werden. Daher sollten diese Felder so schnell wie möglich auf einen gültigen Wert gesetzt werden. Der Konstruktor ist normalerweise ein perfekter Ort dafür. Um sicherzustellen, dass die Variablen während des Konstruktors festgelegt und anschließend nicht geändert werden, können Sie sie mit dem finalSchlüsselwort markieren .

Versuchen Sie, dem Drang zu widerstehen, nulleine Art Flagge oder einen besonderen Wert zu verwenden. Es ist besser, z. B. ein bestimmtes Feld einzuschließen, um den Status zu halten. Ein Feld mit dem Namen state, das die Werte einer StateAufzählung verwendet, wäre eine gute Wahl.

Methodenparameter

Da Änderungen an den Werten von Parametern (seien es Verweise auf Objekte oder Basistypen wie Ganzzahlen usw.) vom Aufrufer nicht gesehen werden, sollten Parameter als markiert werden final. Dies bedeutet, dass die Werte der Variablen selbst nicht geändert werden können. Beachten Sie, dass der Wert von wandelbaren Objektinstanzen kann geändert werden, kann der Verweis nicht auf Punkt zu einem anderen Objekt oder geändert werden , nullthough.

Lokale Variablen

Lokale Variablen werden nicht automatisch initialisiert. Sie müssen initialisiert werden, bevor ihr Wert verwendet werden kann. Eine Methode, um sicherzustellen, dass Ihre Variable initialisiert wird, besteht darin, sie direkt auf einen Standardwert zu initialisieren. Dies sollten Sie jedoch nicht tun. Meistens ist der Standardwert nicht der erwartete Wert.

Es ist viel besser, die Variable nur genau dort zu definieren, wo Sie sie benötigen. Wenn die Variable nur einen einzigen Wert annehmen soll (was für die meisten Variablen in gutem Code gilt), können Sie die Variable markieren final. Dies stellt sicher, dass die lokale Variable genau einmal zugewiesen wird, nicht nullmal oder zweimal. Ein Beispiel:

public static doMethod(final int x) {
    final int y; // no assignment yet, it's final so it *must* be assigned
    if (x < 0) {
        y = 0;
    } else if (x > 0) {
        y = x;
    } else {
        // do nothing <- error, y not assigned if x = 0
        // throwing an exception here is acceptable though
    }
}

Beachten Sie, dass viele Sprachen Sie warnen, wenn eine Variable vor der Verwendung nicht initialisiert wird. Überprüfen Sie die Sprachspezifikationen und Foren, um festzustellen, ob Sie sich keine unnötigen Sorgen machen müssen.

Maarten Bodewes
quelle
1

Es gibt kein Problem mit der Nichtinitialisierung von Variablen.

Das Problem ist nur, wenn Sie eine Variable lesen, die noch nicht geschrieben wurde.

Abhängig vom Compiler und / oder von der Art der Variablen wird die Initialisierung beim Start der Anwendung durchgeführt. Oder nicht.

Es ist üblich, sich nicht auf die automatische Initialisierung zu verlassen.

Mouviciel
quelle
0

Das Initialisieren von Variablen (implizit oder explizit) ist entscheidend. Das Nichtinitialisieren einer Variablen ist immer ein Fehler (sie können jedoch implizit initialisiert werden. Siehe unten). Moderne Complier wie der C # -Compiler (als Beispiel) behandeln dies als Fehler und lassen Sie den Code nicht ausführen. Eine nicht initialisierte Variable ist einfach nutzlos und schädlich. Sofern Sie keinen Zufallszahlengenerator erstellen, erwarten Sie von einem Code ein deterministisches und reproduzierbares Ergebnis. Dies kann nur erreicht werden, wenn Sie mit initialisierten Variablen arbeiten.

Die wirklich interessante Frage ist, ob eine Variable automatisch initialisiert wird oder ob Sie dies manuell tun müssen. Dies hängt von der verwendeten Sprache ab. In C # werden beispielsweise Felder, dh "Variablen" auf Klassenebene, immer automatisch auf den Standardwert für diesen Variablentyp initialisiert default(T). Dieser Wert entspricht einem Bitmuster, das aus allen Nullen besteht. Dies ist Teil der Sprachspezifikation und nicht nur ein technisches Detail der Implementierung der Sprache. Deshalb können Sie sich sicher darauf verlassen. Es ist sicher, eine Variable nicht explizit zu initialisieren, wenn (und nur wenn) die Sprachspezifikation angibt, dass sie implizit initialisiert wird.Wenn Sie einen anderen Wert wünschen, müssen Sie die Variable explizit initialisieren. Jedoch; In C # werden lokale Variablen, dh in Methoden deklarierte Variablen, nicht automatisch initialisiert, und Sie müssen die Variable immer explizit initialisieren.

Olivier Jacot-Descombes
quelle
2
Dies ist keine C # -spezifische Frage.
DougM
@ DougM: Ich weiß. Es ist keine C # -spezifische Antwort, ich habe nur C # als Beispiel genommen.
Olivier Jacot-Descombes
Nicht für alle Sprachen müssen Variablen explizit initialisiert werden. Ihre Aussage "Nicht initialisieren ist immer ein Fehler" ist falsch und fügt der vorliegenden Frage keine Klarheit hinzu. Vielleicht möchten Sie Ihre Antwort überarbeiten.
DougM
@DougM: Haben Sie meinen Satz "Die wirklich interessante Frage ist, ob eine Variable automatisch initialisiert wird oder ob Sie dies manuell tun müssen" überwacht?
Olivier Jacot-Descombes
Du meinst den, der auf halber Höhe in der Mitte eines Absatzes begraben liegt? Ja. Sie sollten es bekannter machen und Ihrem "immer" -Anspruch ein Qualifikationsmerkmal hinzufügen.
DougM