Erfassen C ++ 11-Lambdas Variablen, die sie nicht verwenden?

123

Wenn ich anzeige [=], dass alle lokalen Variablen nach Wert in einem Lambda erfasst werden sollen, werden dann alle lokalen Variablen in der Funktion kopiert oder nur alle lokalen Variablen , die vom Lambda verwendet werden ?

Also zum Beispiel, wenn ich habe:

vector<int> my_huge_vector(100000);
int my_measly_int;
some_function([=](int i){ return my_measly_int + i; });

Wird my_huge_vector kopiert, obwohl ich es nicht im Lambda verwende?

HighCommander4
quelle

Antworten:

114

Jede in der Erfassungsliste ausdrücklich genannte Variable wird erfasst. Die Standard - Capture werden nur Variablen erfassen , die sowohl (a) nicht ausdrücklich in der Aufnahmeliste genannt und (b) verwendet , in dem Körper des Lambda - Ausdrucks. Wenn eine Variable nicht ausdrücklich benannt ist und Sie die Variable nicht im Lambda-Ausdruck verwenden, wird die Variable nicht erfasst. In Ihrem Beispiel my_huge_vectorwird nicht erfasst.

Gemäß C ++ 11 §5.1.2 [expr.prim.lambda] / 11:

Wenn einem Lambda-Ausdruck ein Capture-Standard und seine zusammengesetzte Anweisung odr-used this oder eine Variable mit automatischer Speicherdauer zugeordnet sind und die von odr verwendete Entität nicht explizit erfasst wird, wird die von odr verwendete Entität implizit erfasst.

Ihrem Lambda-Ausdruck ist ein Erfassungsstandard zugeordnet: Standardmäßig erfassen Sie Variablen anhand des Werts mit [=].

Wenn und nur wenn eine Variable verwendet wird (im Sinne der One Definition Rule des Begriffs "verwendet"), wird eine Variable implizit erfasst. Da Sie my_huge_vectorden Body (die "zusammengesetzte Anweisung") des Lambda-Ausdrucks überhaupt nicht verwenden, wird er nicht implizit erfasst.

Weiter mit §5.1.2 / 14

Eine Entität wird durch Kopieren erfasst, wenn

  • Es wird implizit erfasst und der Erfassungsstandard ist =oder wenn
  • Es wird explizit mit einer Erfassung erfasst, die keine enthält &.

Da Ihr my_huge_vectornicht implizit erfasst wird und es nicht explizit erfasst wird, wird es überhaupt nicht erfasst, weder durch Kopie noch durch Referenz.

James McNellis
quelle
10
Hast du ein heiliges Zitat?
GManNickG
Ich werde jedoch sagen, dass die Gesamtheit von §5.1.2 wichtig ist, um alle Details zu verstehen. In diesem Abschnitt sind viele Fachbegriffe definiert, und da die Definitionen der verschiedenen Komponenten von Lambda-Ausdrücken notwendigerweise miteinander verflochten sind, ist es schwierig, kurze Anführungszeichen zu ziehen, die definitiv sagen: "Dies ist X und deshalb X."
James McNellis
Pingen Sie hier für Ihre Aufmerksamkeit , was besagt, dass eine solche Optimierung zumindest für explizit benannte Variablen nicht zulässig ist. Ich bin mir nicht sicher, wo ich die Grenze ziehen soll.
GManNickG
@GManNickG: Das ist ein mächtig gutes Trolling ;-). Ich brauchte gut drei Klicks auf diesen Link, bis mir klar wurde, dass er tatsächlich auf diese Seite verweist ...: -O [Auf jeden Fall werde ich die Sprachspezifikation erneut lesen, wenn ich morgen früh im Büro bin und sie aktualisiere die Antwort angemessen.]
James McNellis
Oh Mist, sorry !!! Meine Frage wurde beantwortet, ich wollte stattdessen hier verlinken . Das muss furchtbar verwirrend gewesen sein.
GManNickG
16

Nein, my_huge_vectorwird nicht erfasst. [=]bedeutet, dass alle verwendeten Variablen im Lambda erfasst werden.

Thomas Minor
quelle
6
Ja. Beachten Sie, dass verwendet ein technisches Wort, aber, und wirklich bedeutet , dass die One Definition Rule verwendet . Betrachten Sie zum Beispiel void f() { const int size(10); [] { int x[size]; }; }. Hier sizewird nicht erfasst, aber das ist in Ordnung, da es nicht im ODR-Sinne verwendet wird. (Visual C ++ 2010 akzeptiert diesen Code nicht, entweder weil sich die Spezifikation nach der Veröffentlichung von VC10 geändert hat oder aufgrund eines Fehlers. Vermutlich wird dies in einer kommenden Version behoben. G ++ 4.5.1 akzeptiert ihn.)
James McNellis
@ JamesMcNellis Keine Sorge, MSVC ist auch heute noch ein Haufen stinkender Scheiße. vgl. godbolt.org/z/vHnnCX (check in gcc für den lulz). Das gesagt; Ich verstehe nicht, warum ein in einem ausgewerteten Ausdruck vorkommender Bezeichner nicht ODR-verwendet wird. Ich denke, dieser Fall wird definitiv ODR-verwendet, es sei denn, Sie meinen, er könnte als constexpr interpretiert werden, also ist nur der Wert nützlich? Ich bin nicht sicher, ob der Compiler davon ausgeht, dass constDinge möglicherweise nicht mutieren. es sei denn, vielleicht super aggressive Optimierungsflagge OX oder so.
v.oddou