C++0x Lambdas-Codierungsstil

Ich frage mich, wie die Leute C++0x Lambdas verwenden, in Bezug auf den Codierungsstil. Die interessanteste Frage ist, wie gründlich beim Schreiben der Erfassungsliste zu sein. Einerseits erlaubt die Sprache, erfasste Variablen explizit aufzulisten, und durch die "explizitist ist besser als implizite Regel" wäre es daher sinnvoll, eine erschöpfende Auflistung zu erstellen, um die Intetion klar anzugeben. Z.B.:

 int sum;
 std::for_each(xs.begin(), xs.end(), [&sum](int x) { sum += x });

Ein weiteres Argument dafür ist, dass, da sich die Lebensdauer von Ref-Gefangenen-Lokalen nicht ändert, nur weil sie gefangen sind (und so kann ein Lambda leicht auf einen Lokalen verweisen, dessen Lebensdauer lange abgelaufen ist), hilft das explizite Erfassen, solche Fehler zu reduzieren und aufzuspüren.

Andererseits bietet die Sprache bewusst auch eine Abkürzung für die automatische Erfassung aller referenzierten Locals, so klar ist es beabsichtigt, verwendet zu werden. Und man könnte behaupten, dass für ein Beispiel wie eines oben, es ist sehr klar, was passiert, auch mit Auto-Capture, und die Lebensdauer von Lambda ist so, dass es nicht überdauern die umgebende Umfang, so gibt es keinen Grund, es nicht zu verwenden:

 int sum;
 std::for_each(xs.begin(), xs.end(), [&](int x) { sum += x });

Offensichtlich muss dies nicht alles oder nichts sein, aber es muss einige Gründe zu entscheiden, wann auto-capture , und wann die Erfassung explizit zu tun ist. Irgendwelche Gedanken?

Eine andere Frage in der gleichen Ader ist, wann Capture-by-Copy - [=], and when to use capture-by-reference - zu verwenden ist, und wann Capture-by-Reference - [&]. Capture-by-copy is obviously safer because there are no lifetime issues, so one could argue that it should be used by default whenever there's no need to mutate the captured value (or see the changes done to it from elsewhere), and capture-by-reference should be treated as (potentially premature) optimization in such cases, to be applied only where it clearly makes a difference. verwendet werden soll. Capture-by-Copy ist offensichtlich sicherer, da es keine lebenslangen Probleme gibt, so dass man argumentieren könnte, dass es standardmäßig verwendet werden sollte, wenn es nicht notwendig ist, den erfassten Wert zu mutieren (oder die Änderungen zu sehen, die von anderswo vorgenommen wurden), und Capture-by-Reference sollte in solchen Fällen als (potenziell vorzeitige) Optimierung behandelt werden, die nur dann angewendet werden sollte, wenn es einen eindeutigen Unterschied macht.

Auf der anderen Seite ist Capture-by-Reference fast immer schneller (vor allem, da es oft bis zu einer Kopie optimiert werden kann, wenn letztere tatsächlich schneller ist, für kleine Typen und inlinefähige Vorlagenfunktionen wie die meisten STL-Algorithmen) und sicher ist, wenn Lambda seinen Umfang nie überlebt (was auch bei allen STL-Algorithmen der Fall ist), so dass die Standardeinstellung auf Capture-by-Referenz in diesem Fall eine triviale und harmlose Optimierung ist, die nicht weh tut.

Was denken Sie?

Antwort auf "C++0x Lambdas-Codierungsstil " 5 von antworten

Mein anfänglicher Instinkt war, dass die Erfassung nach Wert mehr oder weniger das gleiche bietet wie Javas anonyme innere Klassen, die eine bekannte Menge sind. Anstatt jedoch den Array-of-Size-1-Trick zu verwenden, wenn der einschließende Bereich veränderbar sein soll, können Sie stattdessen als Verweis erfassen. Es liegt dann in Ihrer Verantwortung, die Dauer des Lambdas auf den Anwendungsbereich des Referands zu beschränken.

In der Praxis stimme ich Ihnen zu, dass die Erfassung durch Referenz die Standardeinstellung beim Umgang mit Algorithmen sein sollte, von denen ich erwarte, dass sie die Mehrheit der Verwendungen sein werden. Eine häufige Verwendung für anonyme innere Klassen in Java sind Listener. Es gibt weniger Schnittstellen im Listener-Stil, die in C++ zu sehen sind, also ist es ein geringerer Bedarf, aber immer noch da. Es könnte am besten sein, sich in solchen Fällen strikt an die Erfassung nach Wert zu halten, um die Möglichkeit von Fehlern zu vermeiden. Wird die Erfassung eines shared_ptr vielleicht ein großes Idiom sein?

Allerdings habe ich noch keine Lambdas verwendet, also habe ich vielleicht etwas Großes verpasst.

Ich habe noch nie von der Regel "explizit ist besser als implizite Regel" gehört, und ich bin nicht damit einverstanden. Es gibt Fälle, in denen es wahr ist, natürlich, aber auch viele Fälle, in denen es nicht ist. Deshalb fügt 0x den Typinferenz mit dem Schlüsselwort auto keyword after all. (and why function template parameters are already inferred when possible) There are plenty of cases where implicit is preferable. hinzu. (und warum Funktionsvorlagenparameter nach Möglichkeit bereits abgeleitet sind) Es gibt viele Fälle, in denen implizit eisern ist.

Ich habe noch nicht wirklich C++ Lambdas verwendet (außer mit der VC10-Beta herumzutollen), aber ich würde mit letzterer die meiste Zeit

std::for_each(xs.begin(), xs.end(), [&](int x) { sum += x });

Meine Argumentation gehen? Warum nicht? Es ist bequem. Es funktioniert. Und es ist einfacher zu pflegen. Ich muss die Erfassungsliste nicht aktualisieren, wenn ich den Körper des Lambda bediene. Warum sollte ich etwas expliziter sagen als ich? Der Compiler kann die Erfassungsliste basierend auf dem, was tatsächlich verwendet wird, herausfinden.

Wie für die Erfassung nach Referenz vs. Wert? Ich würde die gleichen Regeln anwenden wie für reguläre Funktionen. Wenn Sie Referenzsemantik benötigen, erfassen Sie als Referenz. Wenn Sie Kopierssemantik benötigen, tun Sie dies. Wenn dies der Fall ist, bevorzugen Sie den Wert für kleine Typen und den Verweis, wenn das Kopieren teuer ist.

Es scheint nicht anders als die Wahl, die Sie treffen müssen, wenn Sie eine regelmäßige Funktion entwerfen.

Ich sollte wahrscheinlich die Spezifikationen für Lambdas lesen, aber ist nicht der Hauptgrund für explizite Erfassungslisten, so dass Sie einige Variablen nach Wert und andere als Verweis erfassen können?

Ich sehe hier eine neue Codierungsstandardregel! ;)

Dies ist ein bisschen ausgeklügelt, aber nur um einen "Vorteil" zu betonen, explizit zu sein, betrachten Sie Folgendes:

void foo (std::vector<int> v, int x1)
{
  int sum = 0;
  std::for_each (v.begin ()
    , v.end ()
    , [&](int xl) { sum += x1; } 
}

Nun, ich habe absichtlich schlechte Namen usw. dafür gewählt, aber es ist nur, um den Punkt zu veranschaulichen. Wenn wir eine explizite Erfassungsliste verwenden, würde der obige Code nicht kompilieren, aber derzeit wird er es tun.

In einer sehr strengen Umgebung (sicherheitskritisch) kann ich eine Regel wie diese als Teil des Codierungsstandards sehen.

Ich würde mit expliziten Erfassungslisten gehen, wenn überhaupt bequem, wenn Sie eine Menge von Variablen dann erfassen wollen (Sie tun wahrscheinlich etwas falsch und) Sie können den Griff alle [&] capture list. Erfassungsliste verwenden.

Meine Meinung ist, dass explizite Erfassungslisten das Ideal sind und die impliziten Varianten vermieden werden sollten und nur da sind, so dass die Leute keine Code-Mengen eingeben müssen, wenn sie tatsächlich benötigt werden.

Ich lese den folgenden Link, um ein besseres Verständnis von C++ Lambda zu erhalten. Der in den Beispielen verwendete Codierungsstil ist ziemlich ordentlich und ich kann folgen: http://uint32t.blogspot.com/2009/05/using-c0x-lambda-to-replace-boost-bind.html