138

When I use [=] to indicate that I would like all local variables to be captured by value in a lambda, will that result in all local variables in the function being copied, or just all local variables that are used by the lambda?

So, for example, if i I have:

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

Will my_huge_vector be copied, even though I don't use it in the lambda?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
HighCommander4
  • 50,428
  • 24
  • 122
  • 194

2 Answers2

128

Each variable expressly named in the capture list is captured. The default capture will only capture variables that are both (a) not expressly named in the capture list and (b) used in the body of the lambda expression. If a variable is not expressly named and you don't use the variable in the lambda expression, then the variable is not captured. In your example, my_huge_vector is not captured.

Per C++11 §5.1.2[expr.prim.lambda]/11:

If a lambda-expression has an associated capture-default and its compound-statement odr-uses this or a variable with automatic storage duration and the odr-used entity is not explicitly captured, then the odr-used entity is said to be implicitly captured.

Your lambda expression has an associated capture default: by default, you capture variables by value using the [=].

If and only if a variable is used (in the One Definition Rule sense of the term "used") is a variable implicitly captured. Since you don't use my_huge_vector at all in the body (the "compound statement") of the lambda expression, it is not implicitly captured.

To continue with §5.1.2/14

An entity is captured by copy if

  • it is implicitly captured and the capture-default is = or if
  • it is explicitly captured with a capture that does not include an &.

Since your my_huge_vector is not implicitly captured and it is not explicitly captured, it is not captured at all, by copy or by reference.

Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 11
    Does thou hath a Holy Quote? – GManNickG May 30 '11 at 23:20
  • I will say, though, that the entirety of §5.1.2 is important to understand all of the details. There are a lot of technical terms defined in that section and because the definitions of the various components of lambda expressions are necessarily entangled, it is difficult to pull out short quotes that definitively say "this is X and this is why X." – James McNellis May 30 '11 at 23:33
  • Pinging for your attention [here](http://stackoverflow.com/questions/6181464/c11-lambda-capture-semantics), which says such optimization is not allowed, at least for explicitly named variables. I'm not sure where to draw the line. – GManNickG Oct 03 '12 at 23:54
  • @GManNickG: That is some mighty good trolling ;-). It took me a good three clicks of that link before I realized it actually did point to this page... :-O [In any case, I'll re-read the language spec when I get into the office tomorrow morning and update the answer appropriately.] – James McNellis Oct 04 '12 at 05:55
  • Oh crap, sorry!!! My question was answered, I meant to link [here](http://stackoverflow.com/a/12718425/87234) instead. That must have been awfully confusing. – GManNickG Oct 04 '12 at 06:24
  • If `my_huge_vector` was redefined in the lambda, is it safe to assume that it still wont implicitly capture `my_huge_vector`? – Nadir Muzaffar Oct 15 '12 at 20:27
  • Sorry, forgot to actually finish my question. – Nadir Muzaffar Oct 15 '12 at 20:30
  • Correct, then the name in the lambda expression body would hide the name in the enclosing scope. – James McNellis Oct 15 '12 at 20:31
  • I think there's one missing quote, i.e. §7.5.5.2/10.2: "For each entity captured by copy, an unnamed non-static data member is declared in the closure type.", since the original question is really asking if my_huge_vector is definitely copied into the unnamed closure type or not, and the §7.5.5.2/10.2 bridges the gap between the abstract term "captured" and the concrete implementation constraints (i.e. "unnamed non-static member") – Weipeng Nov 10 '20 at 23:26
19

No, my_huge_vector will not be captured. [=] means all used variables are captured in the lambda.

Thomas Minor
  • 657
  • 3
  • 8
  • 6
    Yep. Note that _used_ is a technical word, though, and really means the One Definition Rule _used_. So, for example, consider `void f() { const int size(10); [] { int x[size]; }; }`. Here, `size` is not captured but that's okay because it isn't used in the ODR sense. (Visual C++ 2010 does not accept this code, either because the spec changed after VC10 was released or due to a bug, presumably this will be fixed in a forthcoming version; g++ 4.5.1 accepts it.) – James McNellis May 31 '11 at 02:21
  • @JamesMcNellis dpn't worry, MSVC is still a pile of smelly crap today. cf. https://godbolt.org/z/vHnnCX (check in gcc for the lulz). That said; I don't understand why any identifier appearing in an evaluated expression wouldn't be ODR-used. I think this case definitely is ODR-used unless you mean it could be interepreted as a constexpr thus only the value is useful ? I'm not sure the compiler assumes `const` stuff don't potentially mutate. unless maybe super aggressive optimization flag OX or stuff. – v.oddou May 24 '19 at 02:31