Frage

Normalerweise werden Sie AWL-Code wie diese finden:

for (SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
{
}

Aber wir haben tatsächlich die Empfehlung es wie folgt zu schreiben:

SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin();
SomeClass::SomeContainer::iterator IterEnd = m_SomeMemberContainerVar.end();
for (; Iter != IterEnd; ++Iter)
{
}

Wenn Sie über Scoping besorgt sind, fügen Sie geschweifte Klammern:

{
    SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin();
    SomeClass::SomeContainer::iterator IterEnd = m_SomeMemberContainerVar.end();
    for (; Iter != IterEnd; ++Iter)
    {
    }
}

Dies soll eine Geschwindigkeit und Effizienzgewinn geben, vor allem, wenn Sie Programmierkonsolen sind, weil die .end () Funktion nicht bei jeder Iteration der Schleife aufgerufen wird. Ich nehme nur die Performance-Verbesserung für selbstverständlich, es klingt vernünftig, aber ich weiß nicht, wie viel und es hängt sicherlich von der Art des Behälters und die tatsächlichen STL-Implementierung verwendet wird. Aber diese Art jetzt für ein paar Monate genutzt haben, ziehe ich es tatsächlich über die erste sowieso.

Der Grund dafür ist die Lesbarkeit: die für die Linie ist sauber und ordentlich. Mit Qualifier und Membervariablen in Code realer Produktion ist es ganz einfach haben wirklich lange Linien, wenn Sie den Stil im ersten Beispiel. Deshalb habe ich machte es absichtlich einen horizontalen Scrollbar in diesem Beispiel haben, nur damit Sie sehen, was ich rede. ;)

Auf der anderen Seite, Sie plötzlich die Iter Variablen auf den äußeren Umfang der for-Schleife einzuführen. Aber dann, zumindest in der Umgebung i in Arbeit wären die Iter zugänglich waren im äußeren Umfang auch in dem ersten Beispiel.

Was ist Ihre Meinung dazu? Gibt es Profis zur ersten Stil anders als möglicherweise den Umfang der Iter Begrenzung?

War es hilfreich?

Lösung

Wenn Sie Ihren Code in Zeilen richtig wickeln, würde die Inline-Form ebenso lesbar sein. Außerdem sollten Sie die iterEnd = container.end() als Optimierungs immer tun:

for (SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin(),
    IterEnd = m_SomeMemberContainerVar.end();
    Iter != IterEnd;
    ++Iter)
{
}

Update:. Fest den Code per paercebal Rat

Andere Tipps

Eine weitere Alternative ist ein foreach Makro zu verwenden, zum Beispiel boost foreach :

BOOST_FOREACH( ContainedType item, m_SomeMemberContainerVar )
{
   mangle( item );
}

Ich weiß, dass Makros in modernen c abgeraten ++, aber bis das Schlüsselwort auto ist weit verbreitet dies der beste Weg ist, die ich gefunden habe, etwas zu bekommen, die prägnant und lesbar ist, und nach wie vor vollständig typsicher und schnell. Sie können Ihren Makro je nachdem, was die Initialisierung Stil bekommt man eine bessere Leistung implementieren.

Es gibt auch einen Hinweis auf die verlinkte Seite über BOOST_FOREACH als foreach Neudefinition der lästigen alle Kappen zu vermeiden.

Die erste Form (innerhalb der for-Schleife) ist besser, wenn der Iterator nicht nach dem for-Schleife nötig ist. Es begrenzt den Anwendungsbereich auf die for-Schleife.

Ich bezweifle ernsthaft, dass es eine Effizienz ist so oder so gewinnen. Es kann auch mit einem typedef gemacht besser lesbar werden.

typedef SomeClass::SomeContainer::iterator MyIter;

for (MyIter Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
{
}

würde ich kürzeren Namen empfehlen; -)

Nachdem auf diese in g ++ sah bei -O2 Optimierung (nur spezifisch zu sein)

Es gibt keinen Unterschied in dem generierten Code für std :: vector, std :: list und std :: map (und Freunde). Es ist ein winziges Kopf mit std :: deque.

in der Regel also aus anwendungstechnischer Sicht macht es wenig Unterschied.

Nein, es ist eine schlechte Idee, einen Einfluß auf iter.end() zu erhalten, bevor die Schleife beginnt. Wenn Ihre Schleife den Behälter ändert dann kann das Ende Iterator für ungültig erklärt werden. Außerdem wird die end() Verfahren garantiert O sein (1).

Vorzeitige Optimierung ist die Wurzel allen Übels ist.

Auch kann der Compiler sein schlauer als Sie denken.

Ich habe nicht eine besonders starke Meinung der einen oder der anderen, obwohl Iterator Lebensdauer mich in Richtung der for-scoped Version anlehnen würde.

Allerdings Lesbarkeit kann ein Problem sein; das kann durch die Verwendung eines typedef geholfen werden, so dass die Iteratortyp ein bisschen mehr überschaubar ist:

typedef SomeClass::SomeContainer::iterator sc_iter_t;

for (sc_iter_t Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
{
}

Nicht eine große Verbesserung, aber ein bisschen.

Ich habe keine Konsole Erfahrung, aber in den meisten modernen C ++ compiliers entweder Option endet equivilent für die Frage des Geltungsbereichs der Ausnahme zu sein. Das Visual Studio Kompilier wird praktisch immer auch im Debug-Code zu setzen, den Zustand Vergleich in einer impliziten temporären Variable (in der Regel ein Register). Während also logisch sieht es aus wie das Ende () -Aufruf durch jede Iteration gemacht wird, macht die optimierte kompilierten Code tatsächlich nur den Anruf einmal und der Vergleich ist die einzige Sache, die jede subsiquent Zeit durch die Schleife durchgeführt wird.

Dies kann nicht der Fall auf Konsolen sein, aber man konnte die Schleife zu überprüfen, um zu sehen unassemble wenn die Optimierung stattfindet. Wenn ja, dann können Sie Sie, was Stil Sie bevorzugen oder in Ihrer Organisation Standard.

Es kann unzusammenhängend Code machen, aber Ich mag es auch in eine separate Funktion ziehen, und übergeben die beiden Iteratoren es.

doStuff(coll.begin(), coll.end())

und haben ..

template<typename InIt>
void doStuff(InIt first, InIt last)
{
   for (InIt curr = first; curr!= last; ++curr)
   {
       // Do stuff
   }
 }

Aktivitäten mögen:

  • müssen Sie nie die hässliche Iteratortyp erwähnen (oder darüber nachdenken, ob es const oder nicht-const)
  • Wenn es Gewinn aus nicht aufrufen end () bei jeder Iteration ist, erhalte ich es

Reise nicht mögen:

  • bricht den Code
  • nach oben
  • Overhead von zusätzlichen Funktionsaufruf.

Aber eines Tages werden wir Lambdas haben!

Ich glaube nicht, dass es schlechter Stil ist überhaupt. Nur typedefs verwenden, um die STL Ausführlichkeit und lange Schlangen zu vermeiden.

typedef set<Apple> AppleSet;
typedef AppleSet::iterator  AppleIter;
AppleSet  apples;

for (AppleIter it = apples.begin (); it != apples.end (); ++it)
{
   ...
}

Spartan Programmierung ist eine Möglichkeit, Ihren Stil Bedenken zu mildern.

Sie können Klammern um die Initialisierung und Schleife aus, wenn Sie sich Sorgen um Umfang sind. Oft, was werde ich tun, ist Iteratoren zu Beginn der Funktion deklariert und sie im gesamten Programm wiederverwendet werden.

Ich bin mit Ferruccio. Die erste Art könnte von einigen bevorzugt, um das Ende () aufrufen, aus der Schleife zu ziehen.

Ich könnte auch hinzufügen, dass C ++ 0x tatsächlich beide Versionen machen viel sauberer:

for (auto iter = container.begin(); iter != container.end(); ++iter)
{
   ...
}

auto iter = container.begin();
auto endIter = container.end();
for (; iter != endIter; ++iter)
{
   ...
}

Ich würde in der Regel schreiben:

SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin(),
                                   IterEnd = m_SomeMemberContainerVar.end();

for(...)

Ich finde die zweite Option mehr lesbar, da Sie nicht mit einer riesigen Linie enden. Allerdings Ferruccio bringt einen guten Punkt über den Umfang auf.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top