6 Stimmen

c++ für Schleife temporäre Variable verwenden

Welche der folgenden Möglichkeiten ist besser und warum? (Speziell für C++)

a.

int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

b.

for( int i(0);i < vec.length(); ++i)
{
  //loop body
}

Ich habe Ratschläge für (a) wegen des Aufrufs der Längenfunktion gesehen. Das beunruhigt mich. Optimiert nicht jeder moderne Compiler (b) so, dass es ähnlich wie (a) ist?

1 Stimmen

Sollte wahrscheinlich in vec.size() geändert werden

1 Stimmen

Sehr interessante Antworten. Erstaunlich, wie einfache Fragen auf Stack Overflow eine Quelle für große Bildung sein können.

1 Stimmen

@Amod: Bitte beachten Sie die Antwort von Andrew Shepherd: die beiden von Ihnen angegebenen Codeblöcke sind NICHT gleichwertig!

13voto

Andrew Shepherd Punkte 42283

Beispiel (b) hat eine andere Bedeutung als Beispiel (a), und der Compiler muss es so interpretieren, wie Sie es schreiben.

Wenn ich (aus irgendeinem erfundenen Grund, der mir nicht einfällt) einen Code geschrieben habe, der dies ermöglicht:

for( int i(0);i < vec.length(); ++i)
{
    if(i%4 == 0)
       vec.push_back(Widget());
}

Ich hätte wirklich nicht gewollt, dass der Compiler jeden Aufruf von vec.length() optimiert, weil ich dann andere Ergebnisse erhalten würde.

1 Stimmen

Perfekte Antwort. Sie sollten vielleicht noch hinzufügen, dass, wenn Sie die Länge des Vektors innerhalb der Schleife nicht ändern, das Konstrukt (a) in der Frage (oder einige der ähnlichen Vorschläge in den anderen Antworten) vorzuziehen ist, weil es für den Compiler schwierig ist, den Aufruf von length() zu optimieren

4 Stimmen

Compiler-Optimierung oder nicht, wenn Sie Iterator mit begin() - end() verwenden, erhalten Sie den Endzeiger einmal und Sie müssen sich nicht um die Größe und alles andere kümmern ...

10voto

Assaf Lavie Punkte 67504

Ich mag:

for (int i = 0, e = vec.length(); i != e; ++i)

Natürlich würde dies auch für Iteratoren funktionieren:

for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)

Ich mag das, weil es sowohl effizient ist (Aufruf end() nur ein einziges Mal), und auch relativ kurz (man muss nur die vector<int>::const_iterator einmal).

0 Stimmen

Dieser Ansatz scheint mir besser lesbar zu sein. Ist er in einem Buch dokumentiert? In welchem? Ich lese dies zum ersten Mal auf Stackoverflow.

1 Stimmen

Nein, end mehr als einmal aufgerufen wird, aber da der Aufruf inlined ist, spielt das keine Rolle.

0 Stimmen

@Konrad, warum sagen Sie, dass end im 2. Beispiel mehr als einmal aufgerufen wird? Wie oft wird es Ihrer Meinung nach aufgerufen (und warum)?

5voto

rlbond Punkte 62333

Ich bin überrascht, dass niemand das Offensichtliche gesagt hat:

In 99,99 % der Fälle spielt das keine Rolle.

Es sei denn, Sie verwenden einen Container, in dem die Berechnung size() eine teure Operation ist, ist es unvorstellbar, dass Ihr Programm auch nur ein paar Nanosekunden langsamer wird. Ich würde sagen, bleiben Sie bei der besser lesbaren Variante, bis Sie ein Profil Ihres Codes erstellen und feststellen, dass size() ist ein Engpass.

1 Stimmen

Es bedeutet etwas anderes! Es ist also fait Materie!

3 Stimmen

In 99,99 % der Fälle spielt das keine Rolle. Es ist nur von Bedeutung, (a) wenn sich size() innerhalb der Schleife ändert, oder (b) wenn die Überprüfung von size() untragbar langsam ist.

3voto

xtofl Punkte 39285

Hier gibt es zwei Fragen zu diskutieren:

  1. Der Umfang der Variablen
  2. Die Neubewertung der Endbedingungen

Variabler Umfang

Normalerweise brauchen Sie die Schleifenvariable nicht außerhalb der Schleife sichtbar zu machen. Deshalb können Sie sie innerhalb der for konstruieren.

Neubewertung des Endzustands

Andrew Shepherd hat es sehr schön ausgedrückt: Es bedeutet etwas anderes, einen Funktionsaufruf in die Endbedingung zu setzen:

for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
   if( ... ) v.push_back( i ); // contrived, but possible
}

// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}

2voto

DevSolar Punkte 63096

Das hat nichts damit zu tun:

Warnung: Vergleich zwischen Ganzzahl mit und ohne Vorzeichen.

Der richtige Typ für Array- und Vektorindizes ist größe_t .

Streng nach gesprochen, in C++ ist es sogar std::vector<>::size_type .

Erstaunlich, wie viele C/C++-Entwickler dies immer noch falsch verstehen.

3 Stimmen

Ja - zumal die richtige Antwort vector<>::size_type und nicht size_t lautet.

0 Stimmen

Streng genommen, ja, Sie haben Recht. Aber ich wäre schon froh, size_t zu sehen, und die Chancen, die Leute zur Verwendung von vector<>::size_type sind ... vernachlässigbar.

0 Stimmen

Der Wert der Verwendung von vector<>::size_type gegenüber size_t ist ebenfalls vernachlässigbar. Es ist nur in Fällen nützlich, in denen man bereits mit einem Template-Container arbeitet (in diesem Fall ist container_type::size_type expliziter als size_t).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X