Ist es gut, eine Variable innerhalb einer Schleife zu definieren? [geschlossen]

15

Mein Lehrer hat mir einmal gesagt, dass ich keine Variable innerhalb einer Schleife definieren soll , aber ich verstehe ehrlich gesagt immer noch nicht warum.

Was sind die Nachteile davon?

Könnte mir jemand das erklären?

user3260672
quelle
7
Welche Programmiersprache unterrichtete Ihr Lehrer?
Brian
2
Wenn Sie eine Variable mit einem nicht-primitiven Typ in einer Schleife definieren, wird Ihr Programm möglicherweise jedes Mal, wenn Sie die Schleife durchlaufen, seinen Konstruktor unnötig aufrufen. Wenn Sie es nur einmal außerhalb der Schleife definieren müssen, tun Sie dies.
Brandin
17
Wenn Sie solche Verwirrung darüber haben, was ein Ausbilder sagt, ist die beste Ressource, den Ausbilder zu fragen. Sie können Ihnen die dichte hin und her Kommunikation geben, die eine Q & A-Site nicht bieten kann.
1
Standortübergreifendes Duplizieren: Unterschied zwischen der Deklaration von Variablen vor oder in einer Schleife? (und natürlich viele, viele Duplikate auf dieser Site für solch eine elementare Frage (einschließlich derjenigen, die sich nur mit C ++ befassen).
Peter Mortensen
2
Dieser Rat war kontextspezifisch. Aus persönlichen constGründen ziehe ich es vor, meine Variablen zu deklarieren, es sei denn, es gibt einen Grund, dies nicht zu tun (eine Gewohnheit der funktionalen Programmierung). Entweder ich werde sie nicht ändern und das Optimierungsprogramm sollte erkennen, wenn sie nicht benötigt werden, oder ich werde und ich habe einen schwerwiegenden Fehler verhindert. Wenn diese konstanten Zwischenwerte für eine Iteration der Schleife spezifisch sind, bedeutet dies, dass sie innerhalb der Schleife deklariert werden. Ein anderes Mal, wenn Sie Variablen außerhalb der Schleife deklarieren müssen, müssen Sie sie außerhalb der Schleife referenzieren. Zum Beispiel die Ergebnisse, die Sie speichern.
Davislor

Antworten:

43

Es ist kein Problem , eine Variable innerhalb einer Schleife zu definieren . In der Tat ist es eine gute Praxis, da Bezeichner auf den kleinstmöglichen Bereich beschränkt sein sollten.

Schlecht ist es , eine Variable innerhalb einer Schleife zuzuweisen, wenn Sie sie auch einmal zuweisen könnten, bevor die Schleife ausgeführt wird. Je nachdem, wie komplex die rechte Seite der Zuweisung ist, kann dies ziemlich teuer werden und sogar die Laufzeit der Schleife dominieren. Wenn Sie eine Schleife schreiben, die in allen Iterationen denselben berechneten Wert verwendet, sollten Sie sie unbedingt über der Schleife berechnen - das ist wichtiger als die Minimierung ihres Umfangs.

Zur Verdeutlichung: Solange compute()immer derselbe Wert zurückgegeben wird, ist dies

int value = compute();
while (something) {
    doSomething(value);
}

ist schlauer als das:

while (something) {
    int value = compute();
    doSomething(value);
}
Kilian Foth
quelle
2
Wie würden Sie eine Variable in der Schleife definieren und vor der Schleife zuweisen?
Maskierter
6
@MaskedMan, ich glaube du missverstehst. Was Kilian bedeutet, ist, wenn Sie eine Variable haben, der während jeder Iteration einer Schleife derselbe Wert zugewiesen wird, z. B. die gleiche Datumsvariable auf gesetzt ist 1/1/1900, die Variable deklariert werden sollte und der Wert vor der Schleife zugewiesen werden sollte.
ps2goat
2
Ich glaube nicht, dass in den letzten zwanzig Jahren ein Compiler geschrieben wurde (außerhalb eines Undergrad-Compiler-Kurses), der nicht herausfinden würde, dass Sie bei jeder Iteration den gleichen Wert zuweisen und diese Zuweisung aus der Schleife entfernen.
TMN
14
@tmn: Lassen Sie niemals einen Compiler das tun, was Sie trivial selbst mit größerer Code-Klarheit tun können.
Robert Harvey
10
@TMN, nicht unbedingt. Diese Optimierung ist nur möglich, wenn der Compiler nachweisen kann, dass die Berechnung nebenwirkungsfrei ist.
Paul Draper
16

Komplexe Typen haben nicht triviale Konstruktoren und Destruktoren.

Diese werden am Anfang und Ende des Schleifenkörpers aufgerufen (wenn er initialisiert wird und den Gültigkeitsbereich verlässt). Wenn die Initialisierung teuer ist und Speicherplatz benötigt, sollte dies vermieden werden.

Für Trivialtypen ist dies jedoch kein Problem. Die Zuweisung und Freigabe selbst addiert und subtrahiert lediglich einen Wert vom Stapelzeiger. (was optimiert wird)

Ratschenfreak
quelle
Danke, genau die Antwort, die ich gesucht habe!
Gebbissimo
6

Nun, sein Rat ist etwas zu einfach (das ist eine Untertreibung).
Das Folgen reicht von einer guten Idee über wen kümmert es und eine schlechte Idee bis hin zu unmöglich .

  1. Sie sollten es befolgen, wenn die Wiederverwendung billiger ist als die Zerstörung der alten und die Erstellung einer neuen.

    #include <iostream>
    #include <string>
    
    int main() {
        std::string s; // Don't needlessly free the buffer
        while ((std::cin >> s))
            std::cout << s;
    }
  2. Sie sollten es als eine Frage des Stils meiden, wenn es für die Leistung keine Rolle spielt.

    #include <stdio.h>
    #include <stdlib.h>
    int f(int, int);
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            int x = rand(); // Declared here so you don't need to hunt it down.
            printf("%d => %d\n", x, f(x-1, x+i));
        }
    }
  3. Sie sollten es wirklich meiden, wenn es schlechtere Leistung oder die falsche Semantik hat.

    #include <iostream>
    #include <string>
    std::string generate(int);
    
    int main() {
        for(int i = 0; i < 100; ++i) {
            std::string s = generate(i); // Using copy-ellision here
            std::cout << s;
        }
    }
  4. Sie können es nicht befolgen, wenn der verwendete Typ weder das Vertauschen noch die Zuweisung von Verschiebungen oder Kopien zulässt.

    #include <iostream>
    #include <puzzle>
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            Puzzle x(i); // Puzzle is an immutable class. For whatever reasons.
            std::cout << x;
        }
    }
Deduplizierer
quelle
2
Abhängig von Ihrer Definition von "in einer Schleife" kann 1 for (std::string s; std::cin >> s;) ...zu "außerhalb" geändert werden und immer noch "außerhalb" sein
Caleth