Frage

Welche der folgenden ist besser und warum? (Besonders zu 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 gesehen Beratung für (a) wegen des Aufrufs Längenfunktion. Das stört mich. Hat nicht jeder moderne Compiler tun, um die Optimierung von (b) zu ähnlich sein (a)?

War es hilfreich?

Lösung

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

Wenn (aus irgendeinem erfundenen Grunde, dass ich nicht denken kann), schrieb ich Code, dies zu tun:

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

Ich würde wirklich nicht die Compiler wollte jeden Aufruf zu optimieren, um vec.length (), weil ich unterschiedliche Ergebnisse erhalten würde.

Andere Tipps

Ich mag:

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

Natürlich wäre dies auch für Iteratoren arbeiten:

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

Ich mag das, weil es sowohl effizient (Aufruf end() nur einmal) ist, und auch relativ prägnantes (nur mit einmal eingeben vector<int>::const_iterator).

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

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

Wenn Sie einige Behälter verwenden, wo size() Berechnung ist eine teuere Operation ist es unergründlich, dass Ihr Programm geht noch ein paar Nanosekunden langsamer. Ich würde sagen, Stick mit dem besser lesbar, bis Sie Ihren Code Profil und finden, dass size() ein Engpass ist.

Es gibt zwei Probleme zu diskutieren hier:

  1. Die Variable Anwendungsbereich
  2. Die Endbedingung Umwertung

Variable Anwendungsbereich

Normalerweise würden Sie nicht die Schleifenvariable müssen sichtbar außerhalb der Schleife sein. Deshalb sollten Sie es im Inneren des for Konstrukt erklären kann.

Endebedingung Umwertung

Andrew Shepherd es schön gesagt: bedeutet es etwas anderes einen Funktionsaufruf innerhalb des Endes Zustand zu versetzen:

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 ) {
}

Warum ist es bodering Sie? Diese beiden Alternativen nicht sehen, das gleiche zu tun. Man wird eine feste Anzahl von Iterationen zu tun, während der andere auf dem Schleifen Körper abhängig ist.

Eine weitere Alternative colud sein

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

Wenn Sie die Schleifenvariable außerhalb der Schleife müssen, der zweite Ansatz ist vorzuziehen.

Iteratoren werden Sie tatsächlich geben, wie gut oder bessere Leistung. (Es gab einen großen Vergleich Thread auf comp.lang.c ++. Vor ein paar Jahren moderiert).

Auch ich würde verwenden

int i = 0;

Anstatt der Konstruktor wie Syntax Sie verwenden. Während gültig, dann ist es nicht idiomatischen.

Etwas in keinem Zusammenhang:

. Achtung: Ein Vergleich zwischen mit und ohne Vorzeichen integer

Der richtige Typ für Array und Vektorindizes ist size_t .

Strictly zu sprechen, in C ++ ist es sogar std::vector<>::size_type.

Erstaunlich, wie viele C / C ++ Entwickler immer noch dieses falsch.

Lassen Sie uns auf den generierten Code sehen (ich verwende MSVS 2008 mit voller Optimierung).

a.

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

Die for-Schleife erzeugt 2 Assembler-Anweisungen.

b.

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

Die for-Schleife erzeugt 8 Assembler-Anweisungen. vec.size () erfolgreich inlined.

c.

for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
  //loop body
}

Die for-Schleife erzeugt 15 Assembler-Anweisungen (alles inlined, aber der Code eine Menge Sprünge hat)

Also, wenn Ihre Anwendung ist Leistung entscheidend Verwendung a). b Andernfalls) oder c).

Es sollte die Iterator Beispiele zu beachten:

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

könnte die Schleife Iterator ungültig ‚it‘ sollte der Schleifenkörper bewirken, dass der Vektor neu zuzuteilen. So ist es nicht gleichbedeutend mit

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

wo Schleifenkörper fügt Elemente zu vec.

Einfache Frage: sind Sie vec in der Schleife modifiziert

Antwort auf diese Frage wird auch auf Ihre Antwort führen.

JRH

Es ist sehr schwer für einen Compiler des vec.length() Anruf im sicheren Wissen hissen, dass es konstant ist, es sei denn, es inlined wird (was hoffentlich wird es oft!). Aber zumindest i auf jeden Fall in der zweiten Art „b“ erklärt werden soll, auch wenn der length Anruf „von Hand“ hochgezogen werden muss aus der Schleife!

Dieses ist vorzuziehen:

typedef vector<int> container; // not really required,
                               // you could just use vector<int> in for loop

for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
    // do something with (*i)
}
  • Ich kann sofort sagen, dass der Vektor nicht
  • aktualisiert
  • kann jeder sagen, was geschieht hier
  • Ich weiß, wie viele Schleifen
  • v.end() gibt Zeiger eine Vergangenheit die letztes Element, so gibt es keinen Overhead die Überprüfung Größe
  • leicht für verschiedene aktualisieren Container oder Werttypen

(b) wird die Funktion jedes Mal nicht berechnen / nennen.

- beginnen Auszug ----

Schleifeninvariante-Code Motion: GCC umfasst als Teil seiner Schleife Optimierer sowie in seinem teilweisen Redundanzbeseitigung Pass unveränderliche Code-Schleife. Diese Optimierung entfernt Anweisungen von Schleifen, die einen Wert berechnen, die während der gesamten Lebensdauer einer Schleife nicht verändert.

--- Ende Auszug -

Weitere Optimierungen für gcc:

https://www.in.redhat.com/software /gnupro/technical/gnupro_gcc.php3

Warum umgeht das Problem nicht vollständig mit BOOST_FOREACH

#include <boost/foreach.hpp>

std::vector<double> vec;

//...

BOOST_FOREACH( double &d, vec)
{
    std::cout << d;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top