Gibt es irgendwelche Vorteile von std::for_each
Over- for
Loop? Mir std::for_each
scheint nur die Lesbarkeit von Code zu beeinträchtigen. Warum empfehlen dann einige Codierungsstandards die Verwendung?
Gibt es irgendwelche Vorteile von std::for_each
Over- for
Loop? Mir std::for_each
scheint nur die Lesbarkeit von Code zu beeinträchtigen. Warum empfehlen dann einige Codierungsstandards die Verwendung?
Antworten:
Das Schöne an C ++ 11 (früher C ++ 0x genannt) ist, dass diese lästige Debatte beigelegt wird.
Ich meine, niemand, der bei klarem Verstand ist und eine ganze Sammlung durchlaufen möchte, wird dies noch verwenden
for(auto it = collection.begin(); it != collection.end() ; ++it)
{
foo(*it);
}
Oder dieses
for_each(collection.begin(), collection.end(), [](Element& e)
{
foo(e);
});
wenn die bereichsbasierte for
Schleifensyntax verfügbar ist:
for(Element& e : collection)
{
foo(e);
}
Diese Art von Syntax ist seit einiger Zeit in Java und C # verfügbar, und tatsächlich gibt es in jedem neueren Java- oder C # -Code, den ich gesehen habe, weit mehr foreach
Schleifen als klassische for
Schleifen.
Element & e
wie auto & e
(oder auto const &e
) besser aussieht. Ich würde Element const e
(ohne Referenz) verwenden, wenn ich implizite Konvertierung möchte, z. B. wenn die Quelle eine Sammlung verschiedener Typen ist und ich möchte, dass sie in konvertiert werden Element
.
Hier sind einige Gründe:
Es scheint die Lesbarkeit zu beeinträchtigen, nur weil Sie nicht daran gewöhnt sind und / oder nicht die richtigen Tools verwenden, um es wirklich einfach zu machen. (Weitere Informationen finden Sie unter boost :: range und boost :: bind / boost :: lambda. Viele davon werden in C ++ 0x verwendet und for_each und verwandte Funktionen sind nützlicher.)
Sie können einen Algorithmus über for_each schreiben, der mit jedem Iterator funktioniert.
Es verringert die Wahrscheinlichkeit von dummen Tippfehlern.
Es öffnet auch Ihre Meinung zu dem Rest der STL-Algorithmen, wie find_if
, sort
, replace
usw. , und diese werden nicht so seltsam aussehen mehr. Dies kann ein großer Gewinn sein.
Update 1:
Am wichtigsten ist, dass es Ihnen hilft, über for_each
For-for-Schleifen hinauszugehen, wie es alles ist, und sich die anderen STL-Alogs anzusehen, wie find / sort / partition / copy_replace_if, Parallell-Ausführung ... oder was auch immer.
Mit "dem Rest" der Geschwister von for_each kann eine Menge Verarbeitung sehr präzise geschrieben werden. Wenn Sie jedoch nur eine for-Schleife mit verschiedenen internen Logiken schreiben, werden Sie nie lernen, wie man diese verwendet, und Sie werden es tun am Ende immer wieder das Rad erfinden.
Und (der bald verfügbare Range-Style für_each):
for_each(monsters, boost::mem_fn(&Monster::think));
Oder mit C ++ x11 Lambdas:
for_each(monsters, [](Monster& m) { m.think(); });
ist IMO besser lesbar als:
for(Monsters::iterator i = monsters.begin(); i != monsters.end(); ++i) {
i->think();
}
Auch dies (oder mit Lambdas, siehe andere):
for_each(bananas, boost::bind(&Monkey::eat, my_monkey, _1));
Ist prägnanter als:
for(Bananas::iterator i = bananas.begin(); i != bananas.end(); ++i) {
my_monkey->eat(*i);
}
Vor allem, wenn Sie mehrere Funktionen in der richtigen Reihenfolge aufrufen müssen ... aber vielleicht bin das nur ich. ;)
Update 2 : Ich habe meine eigenen Einzeiler-Wrapper von STL-Algen geschrieben, die mit Bereichen anstelle von Iteratorpaaren arbeiten. boost :: range_ex wird das nach seiner Veröffentlichung enthalten und vielleicht auch in C ++ 0x?
outer_class::inner_class::iterator
oder sie sind Vorlagenargumente: typename std::vector<T>::iterator
... das for-Konstrukt selbst kann auf ein Konstrukt mit vielen Zeilen an sich
for_each
im zweiten Beispiel ist falsch (sollte seinfor_each( bananas.begin(), bananas.end(),...
for_each
ist allgemeiner. Sie können es verwenden, um über jeden Containertyp zu iterieren (indem Sie die Start- / End-Iteratoren übergeben). Sie können möglicherweise Container unter einer Funktion austauschen, die verwendet wird, for_each
ohne den Iterationscode aktualisieren zu müssen. Sie müssen berücksichtigen, dass es auf der Welt andere Container als std::vector
einfache C-Arrays gibt, um die Vorteile von zu erkennen for_each
.
Der Hauptnachteil von for_each
ist, dass es einen Funktor braucht, so dass die Syntax klobig ist. Dies wird in C ++ 11 (früher C ++ 0x) mit der Einführung von Lambdas behoben:
std::vector<int> container;
...
std::for_each(container.begin(), container.end(), [](int& i){
i+= 10;
});
Dies wird in 3 Jahren nicht sonderbar für Sie aussehen.
for ( int v : int_vector ) {
(auch wenn es heute mit BOOST_FOREACH simuliert werden kann)
std::for_each(container, [](int& i){ ... });
. Ich meine, warum muss man zweimal Container schreiben?
container.each { ... }
ohne Erwähnung von Anfangs- und Enditeratoren. Ich finde es etwas überflüssig, dass ich ständig den Enditerator angeben muss.
Persönlich finde ich jedes Mal, wenn ich mir die Mühe machen müsste std::for_each
, spezielle Funktionen zu schreiben (spezielle Funktoren / komplizierte boost::lambda
s schreiben ), BOOST_FOREACH
und C ++ 0x ist bereichsbasiert, um klarer zu werden:
BOOST_FOREACH(Monster* m, monsters) {
if (m->has_plan())
m->act();
}
vs.
std::for_each(monsters.begin(), monsters.end(),
if_then(bind(&Monster::has_plan, _1),
bind(&Monster::act, _1)));
sein sehr subjektiv, werden einige sagen , dass die Verwendung for_each
des Code macht mehr lesbar, da es verschiedene Sammlungen mit den gleichen Konventionen zu behandeln ermöglicht.
for_each
itslef ist als Schleife implementiert
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)
{
for ( ; first!=last; ++first ) f(*first);
return f;
}
Es liegt also an Ihnen, zu entscheiden, was für Sie richtig ist.
Wie bei vielen Algorithmusfunktionen besteht eine erste Reaktion darin, zu denken, dass es unlesbarer ist, foreach als eine Schleife zu verwenden. Es war ein Thema vieler Flammenkriege.
Sobald Sie sich an die Redewendung gewöhnt haben, finden Sie sie möglicherweise nützlich. Ein offensichtlicher Vorteil besteht darin, dass der Codierer gezwungen wird, den inneren Inhalt der Schleife von der eigentlichen Iterationsfunktionalität zu trennen. (OK, ich denke, es ist ein Vorteil. Andere sagen, Sie zerhacken nur den Code ohne wirklichen Nutzen).
Ein weiterer Vorteil ist, dass ich weiß, dass entweder jeder Artikel verarbeitet oder eine Ausnahme ausgelöst wird, wenn ich foreach sehe .
Eine for- Schleife bietet verschiedene Möglichkeiten zum Beenden der Schleife. Sie können die Schleife ihren vollen Verlauf nehmen lassen oder das Schlüsselwort break verwenden, um explizit aus der Schleife zu springen, oder das Schlüsselwort return verwenden , um die gesamte Funktion in der Mitte der Schleife zu beenden. Im Gegensatz dazu lässt foreach diese Optionen nicht zu und ist daher besser lesbar. Sie können nur einen Blick auf den Funktionsnamen werfen und kennen die vollständige Art der Iteration.
Hier ist ein Beispiel für eine verwirrende for- Schleife:
for(std::vector<widget>::iterator i = v.begin(); i != v.end(); ++i)
{
/////////////////////////////////////////////////////////////////////
// Imagine a page of code here by programmers who don't refactor
///////////////////////////////////////////////////////////////////////
if(widget->Cost < calculatedAmountSofar)
{
break;
}
////////////////////////////////////////////////////////////////////////
// And then some more code added by a stressed out juniour developer
// *#&$*)#$&#(#)$#(*$&#(&*^$#(*$#)($*#(&$^#($*&#)$(#&*$&#*$#*)$(#*
/////////////////////////////////////////////////////////////////////////
for(std::vector<widgetPart>::iterator ip = widget.GetParts().begin(); ip != widget.GetParts().end(); ++ip)
{
if(ip->IsBroken())
{
return false;
}
}
}
std::for_each()
den alten Standard (den der Zeit dieses Beitrags) verwenden, müssen Sie einen benannten Funktor verwenden, der die Lesbarkeit fördert, wie Sie sagen, und ein vorzeitiges Ausbrechen der Schleife verhindert. Aber dann hat die äquivalente for
Schleife nichts als einen Funktionsaufruf, und auch das verhindert ein vorzeitiges Ausbrechen. Aber abgesehen davon denke ich, dass Sie einen hervorragenden Punkt gemacht haben, indem Sie gesagt haben, dass das Durchlaufen des gesamten Sortiments std::for_each()
erzwungen wird.
Sie haben größtenteils Recht: Meistens std::for_each
handelt es sich um einen Nettoverlust. Ich würde sogar so weit gehen zu vergleichen for_each
zu goto
. goto
bietet die vielseitigste Flusssteuerung, die möglich ist - Sie können damit praktisch jede andere Steuerungsstruktur implementieren, die Sie sich vorstellen können. Diese Vielseitigkeit bedeutet jedoch, dass das goto
isolierte Betrachten praktisch nichts darüber aussagt, was in dieser Situation beabsichtigt ist. Infolgedessen nutzt fast niemand, der bei klarem Verstand ist, goto
außer als letztes Mittel.
Bei den Standardalgorithmen for_each
ist es ähnlich - es kann verwendet werden, um praktisch alles zu implementieren, was bedeutet, dass das Sehen for_each
Ihnen praktisch nichts darüber sagt, wofür es in dieser Situation verwendet wird. Leider geht es bei der Einstellung der Menschen for_each
darum, wo ihre Einstellung zu goto
(etwa) 1970 war - einige Leute hatten die Tatsache begriffen, dass es nur als letztes Mittel verwendet werden sollte, aber viele halten es immer noch für den primären Algorithmus, und Verwenden Sie selten oder nie einen anderen. Die überwiegende Mehrheit der Zeit würde sogar ein kurzer Blick zeigen, dass eine der Alternativen drastisch überlegen war.
Ich bin mir zum Beispiel ziemlich sicher, dass ich den Überblick verloren habe, wie oft ich Leute gesehen habe, die Code geschrieben haben, um den Inhalt einer Sammlung mit auszudrucken for_each
. Basierend auf Beiträgen, die ich gesehen habe, ist dies möglicherweise die häufigste Verwendung for_each
. Sie enden mit so etwas wie:
class XXX {
// ...
public:
std::ostream &print(std::ostream &os) { return os << "my data\n"; }
};
Und ihr Beitrag fragt nach , welche Kombination von bind1st
, mem_fun
usw. müssen sie so etwas wie zu machen:
std::vector<XXX> coll;
std::for_each(coll.begin(), coll.end(), XXX::print);
arbeiten und drucken Sie die Elemente von coll
. Wenn es wirklich genau so funktioniert hätte, wie ich es dort geschrieben habe, wäre es mittelmäßig, aber es funktioniert nicht - und wenn Sie es zum Laufen gebracht haben, ist es schwierig, diese wenigen Code-Teile zu finden, die sich auf das beziehen, was mit dem zu tun hat weiter zwischen den Stücken, die es zusammenhalten.
Zum Glück gibt es einen viel besseren Weg. Fügen Sie eine normale Stream Inserter-Überladung für XXX hinzu:
std::ostream &operator<<(std::ostream *os, XXX const &x) {
return x.print(os);
}
und verwenden std::copy
:
std::copy(coll.begin(), coll.end(), std::ostream_iterator<XXX>(std::cout, "\n"));
Das funktioniert - und es ist praktisch keine Arbeit erforderlich, um herauszufinden, dass der Inhalt von coll
to gedruckt wird std::cout
.
boost::mem_fn(&XXX::print)
eher sein alsXXX::print
std::cout
als Argument binden, damit es funktioniert).
Der Vorteil der Schreibfunktion, um besser lesbar zu sein, zeigt sich möglicherweise nicht, wann for(...)
und for_each(...
).
Wenn Sie alle Algorithmen in function.h verwenden, anstatt for-Schleifen zu verwenden, wird der Code viel besser lesbar.
iterator longest_tree = std::max_element(forest.begin(), forest.end(), ...);
iterator first_leaf_tree = std::find_if(forest.begin(), forest.end(), ...);
std::transform(forest.begin(), forest.end(), firewood.begin(), ...);
std::for_each(forest.begin(), forest.end(), make_plywood);
ist viel besser lesbar als;
Forest::iterator longest_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
if (*it > *longest_tree) {
longest_tree = it;
}
}
Forest::iterator leaf_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
if (it->type() == LEAF_TREE) {
leaf_tree = it;
break;
}
}
for (Forest::const_iterator it = forest.begin(), jt = firewood.begin();
it != forest.end();
it++, jt++) {
*jt = boost::transformtowood(*it);
}
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
std::makeplywood(*it);
}
Und das finde ich so schön, verallgemeinere die for-Schleifen auf einzeilige Funktionen =)
Einfach: for_each
Ist nützlich, wenn Sie bereits über eine Funktion verfügen, mit der jedes Array-Element verarbeitet werden kann, sodass Sie kein Lambda schreiben müssen. Sicher das
for_each(a.begin(), a.end(), a_item_handler);
ist besser als
for(auto& item: a) {
a_item_handler(a);
}
Außerdem durchläuft die for
Fernschleife nur ganze Container von Anfang bis Ende, während for_each
sie flexibler ist.
Die for_each
Schleife soll die Iteratoren (Details zur Implementierung einer Schleife) vor dem Benutzercode verbergen und eine klare Semantik für die Operation definieren: Jedes Element wird genau einmal iteriert.
Das Problem mit der Lesbarkeit im aktuellen Standard besteht darin, dass anstelle eines Codeblocks ein Funktor als letztes Argument erforderlich ist. In vielen Fällen müssen Sie daher einen bestimmten Funktortyp dafür schreiben. Dies führt zu weniger lesbarem Code, da Funktorobjekte nicht direkt definiert werden können (lokale Klassen, die innerhalb einer Funktion definiert sind, können nicht als Vorlagenargumente verwendet werden) und die Implementierung der Schleife von der eigentlichen Schleife entfernt werden muss.
struct myfunctor {
void operator()( int arg1 ) { code }
};
void apply( std::vector<int> const & v ) {
// code
std::for_each( v.begin(), v.end(), myfunctor() );
// more code
}
Beachten Sie, dass Sie, wenn Sie für jedes Objekt eine bestimmte Operation ausführen möchten std::mem_fn
, oder boost::bind
( std::bind
im nächsten Standard) oder boost::lambda
(Lambdas im nächsten Standard) verwenden können, um dies zu vereinfachen:
void function( int value );
void apply( std::vector<X> const & v ) {
// code
std::for_each( v.begin(), v.end(), boost::bind( function, _1 ) );
// code
}
Dies ist nicht weniger lesbar und kompakter als die handgerollte Version, wenn Sie über eine Funktion / Methode zum Aufrufen verfügen. Die Implementierung könnte andere Implementierungen der for_each
Schleife bereitstellen (denken Sie an Parallelverarbeitung).
Der kommende Standard behebt einige der Mängel auf unterschiedliche Weise und ermöglicht lokal definierte Klassen als Argumente für Vorlagen:
void apply( std::vector<int> const & v ) {
// code
struct myfunctor {
void operator()( int ) { code }
};
std::for_each( v.begin(), v.end(), myfunctor() );
// code
}
Verbessern der Lokalität von Code: Wenn Sie surfen, sehen Sie, was er genau dort tut. Tatsächlich müssen Sie nicht einmal die Klassensyntax verwenden, um den Funktor zu definieren, sondern verwenden genau dort ein Lambda:
void apply( std::vector<int> const & v ) {
// code
std::for_each( v.begin(), v.end(),
[]( int ) { // code } );
// code
}
Auch wenn es für den Fall von for_each
ein spezifisches Konstrukt gibt, das es natürlicher macht:
void apply( std::vector<int> const & v ) {
// code
for ( int i : v ) {
// code
}
// code
}
Ich neige dazu, das for_each
Konstrukt mit handgerollten Schleifen zu mischen . Wenn ich nur einen Aufruf einer vorhandenen Funktion oder Methode benötige ( for_each( v.begin(), v.end(), boost::bind( &Type::update, _1 ) )
), greife ich zu dem for_each
Konstrukt, das dem Code eine Menge Kesselplatten-Iterator-Material wegnimmt. Wenn ich etwas Komplexeres brauche und einen Funktor nicht nur ein paar Zeilen über dem tatsächlichen Gebrauch implementieren kann, rolle ich meine eigene Schleife (hält die Operation an Ort und Stelle). In unkritischen Codeabschnitten könnte ich mich für BOOST_FOREACH entscheiden (ein Mitarbeiter hat mich dazu gebracht).
Neben der Lesbarkeit und Leistung wird häufig die Konsistenz übersehen. Es gibt viele Möglichkeiten, eine for (oder while) -Schleife über Iteratoren zu implementieren:
for (C::iterator iter = c.begin(); iter != c.end(); iter++) {
do_something(*iter);
}
zu:
C::iterator iter = c.begin();
C::iterator end = c.end();
while (iter != end) {
do_something(*iter);
++iter;
}
mit vielen Beispielen dazwischen bei unterschiedlichen Effizienz- und Fehlerpotentialen.
Die Verwendung von for_each erzwingt jedoch die Konsistenz, indem die Schleife entfernt wird:
for_each(c.begin(), c.end(), do_something);
Das einzige, worüber Sie sich jetzt Sorgen machen müssen, ist: Implementieren Sie den Schleifenkörper als Funktion, Funktor oder Lambda mithilfe von Boost- oder C ++ 0x-Funktionen? Persönlich würde ich mir lieber darum kümmern, als eine zufällige for / while-Schleife zu implementieren oder zu lesen.
Ich mochte es nicht std::for_each
und dachte, dass es ohne Lambda völlig falsch gemacht wurde. Allerdings habe ich es mir vor einiger Zeit anders überlegt und jetzt liebe ich es wirklich. Ich denke, es verbessert sogar die Lesbarkeit und erleichtert das Testen Ihres Codes auf TDD-Weise.
Der std::for_each
Algorithmus kann mit allen Elementen im Bereich gelesen werden , was die Lesbarkeit verbessern kann . Angenommen, die Aktion, die Sie ausführen möchten, ist 20 Zeilen lang, und die Funktion, in der die Aktion ausgeführt wird, ist ebenfalls etwa 20 Zeilen lang. Das würde eine Funktion mit einer herkömmlichen for-Schleife 40 Zeilen lang und mit einer nur etwa 20 Zeilen lang machen std::for_each
, was wahrscheinlich einfacher zu verstehen ist.
Funktoren für std::for_each
sind eher generisch und daher wiederverwendbar, z.
struct DeleteElement
{
template <typename T>
void operator()(const T *ptr)
{
delete ptr;
}
};
Und im Code hätten Sie nur einen Einzeiler, std::for_each(v.begin(), v.end(), DeleteElement())
der IMO etwas besser ist als eine explizite Schleife.
Alle diese Funktoren sind normalerweise leichter unter Unit-Tests zu finden als eine explizite for-Schleife mitten in einer langen Funktion, und das allein ist für mich bereits ein großer Gewinn.
std::for_each
ist im Allgemeinen auch zuverlässiger, da Sie weniger wahrscheinlich einen Fehler mit der Reichweite machen.
Und schließlich kann der Compiler etwas besseren Code für std::for_each
bestimmte handgefertigte for-Schleifen erzeugen als für bestimmte Arten von handgefertigten for-Schleifen, da er (for_each) für Compiler immer gleich aussieht und Compiler-Autoren ihr gesamtes Wissen einsetzen können, um ihn so gut wie möglich zu machen können.
Gleiches gilt für andere std Algorithmen wie find_if
, transform
usw.
for
ist für eine Schleife, die jedes Element oder jedes Drittel usw. iterieren kann. for_each
dient zum Iterieren nur jedes Elements. Es ist klar aus seinem Namen. Es ist also klarer, was Sie in Ihrem Code vorhaben.
++
. Vielleicht ungewöhnlich, aber auch eine For-Schleife macht das Gleiche.
transform
jemanden nicht zu verwirren.
Wenn Sie häufig andere Algorithmen aus der STL verwenden, gibt es mehrere Vorteile for_each
:
Im Gegensatz zu einer herkömmlichen for-Schleife müssen for_each
Sie Code schreiben, der für jeden Eingabe-Iterator funktioniert. Auf diese Weise eingeschränkt zu sein, kann tatsächlich eine gute Sache sein, weil:
for_each
.Die Verwendung for_each
macht manchmal deutlicher, dass Sie eine spezifischere STL-Funktion verwenden können, um dasselbe zu tun. (Wie in Jerry Coffins Beispiel; es ist nicht unbedingt der Fall, der for_each
die beste Option ist, aber eine for-Schleife ist nicht die einzige Alternative.)
Mit C ++ 11 und zwei einfachen Vorlagen können Sie schreiben
for ( auto x: range(v1+4,v1+6) ) {
x*=2;
cout<< x <<' ';
}
als Ersatz für for_each
oder als Schleife. Warum es auf Kürze und Sicherheit ankommt, es besteht keine Möglichkeit eines Fehlers in einem Ausdruck, der nicht vorhanden ist.
Für mich for_each
war es aus den gleichen Gründen immer besser, wenn der Loop-Body bereits ein Funktor ist, und ich werde jeden Vorteil nutzen, den ich bekommen kann.
Sie verwenden immer noch den Drei-Ausdruck for
, aber wenn Sie jetzt einen sehen, wissen Sie, dass es dort etwas zu verstehen gibt, es ist kein Boilerplate. Ich hasse Boilerplate. Ich ärgere mich über seine Existenz. Es ist kein echter Code, es gibt nichts zu lernen, wenn man ihn liest. Es ist nur eine weitere Sache, die überprüft werden muss. Die mentale Anstrengung kann daran gemessen werden, wie leicht es ist, bei der Überprüfung rostig zu werden.
Die Vorlagen sind
template<typename iter>
struct range_ {
iter begin() {return __beg;} iter end(){return __end;}
range_(iter const&beg,iter const&end) : __beg(beg),__end(end) {}
iter __beg, __end;
};
template<typename iter>
range_<iter> range(iter const &begin, iter const &end)
{ return range_<iter>(begin,end); }
Meistens müssen Sie die gesamte Sammlung durchlaufen . Daher schlage ich vor, dass Sie Ihre eigene for_each () -Variante schreiben und nur 2 Parameter verwenden. Auf diese Weise können Sie das Beispiel von Terry Mahaffey wie folgt umschreiben :
for_each(container, [](int& i) {
i += 10;
});
Ich denke, das ist in der Tat besser lesbar als eine for-Schleife. Dies erfordert jedoch die C ++ 0x-Compiler-Erweiterungen.
Ich finde for_each schlecht für die Lesbarkeit. Das Konzept ist gut, aber C ++ macht es sehr schwer, lesbar zu schreiben, zumindest für mich. c ++ 0x Lamda-Ausdrücke helfen. Ich mag die Idee von Lamdas sehr. Auf den ersten Blick finde ich die Syntax jedoch sehr hässlich und ich bin mir nicht 100% sicher, ob ich mich jemals daran gewöhnen werde. Vielleicht habe ich mich in 5 Jahren daran gewöhnt und nicht weiter darüber nachgedacht, aber vielleicht auch nicht. Wir werden sehen :)
Ich benutze lieber
vector<thing>::iterator istart = container.begin();
vector<thing>::iterator iend = container.end();
for(vector<thing>::iterator i = istart; i != iend; ++i) {
// Do stuff
}
Ich finde eine explizite for-Schleife klarer zu lesen und die Explizität unter Verwendung benannter Variablen für die Start- und End-Iteratoren reduziert die Unordnung in der for-Schleife.
Natürlich variieren die Fälle, das ist genau das, was ich normalerweise am besten finde.
Der Iterator kann ein Aufruf einer Funktion sein, die bei jeder Iteration durch die Schleife ausgeführt wird.
Siehe hier: http://www.cplusplus.com/reference/algorithm/for_each/
for_each
in diesem Fall die Frage nach den Vorteilen nicht beantwortet.
For-Schleife kann brechen; Ich möchte kein Papagei für Herb Sutter sein, daher hier der Link zu seiner Präsentation: http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-835T Lesen Sie auch die Kommentare :)
for_each
Erlauben Sie uns, das Fork-Join-Muster zu implementieren . Ansonsten unterstützt es Fluent-Interface .
Wir können eine Implementierung hinzufügen gpu::for_each
, um cuda / gpu für heterogen-paralleles Rechnen zu verwenden, indem wir die Lambda-Aufgabe in mehreren Workern aufrufen.
gpu::for_each(users.begin(),users.end(),update_summary);
// all summary is complete now
// go access the user-summary here.
Und gpu::for_each
kann warten, bis die Arbeiter an allen Lambda-Aufgaben fertig sind, bevor sie die nächsten Anweisungen ausführen.
Es ermöglicht uns, von Menschen lesbaren Code präzise zu schreiben.
accounts::erase(std::remove_if(accounts.begin(),accounts.end(),used_this_year));
std::for_each(accounts.begin(),accounts.end(),mark_dormant);
std::for_each
bei Verwendung mitboost.lambda
oderboost.bind
kann oft die Lesbarkeit verbessern