Does [=] imply that all local variables will be copied?

C++C++11LambdaCapture

C++ Problem Overview


When I write a lambda with [=], does it mean that all my local variables will be copied into members of the created struct or can I assume that only those will that are actually used in the lambda? For example:

void f()
{
    vector<int> v(10000);
    const int n = 5;
    const int DivByNCnt = count_if(istream_iterator<int>(cin), istream_iterator<int>(), 
          [=](int i)
          {
             return i % n == 0;
          });
}

Which of the following, if any, is true?

  • both n and v will be copied
  • n will be copied, v will not
  • n will be copied, v may or may not be copied depending on the implmenentation/optimization settings.

Suppose for the argument's sake that vector's copy constructor has side effects.

C++ Solutions


Solution 1 - C++

No. It just means that all local variables from the ambient scope are available for lookup inside the body of the lambda. Only if you refer to a name of an ambient local variable will that variable be captured, and it'll be captured by value.

The "capture anything" shorthands = and & are just syntactic sugar, essentially, telling the compiler to "figure out what I mean".


A formal reference from 5.1.2/11-12:

> If a lambda-expression has an associated capture-default and its compound-statement odr-uses [...] 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 [...] > > An entity is captured if it is captured explicitly or implicitly.

Note that "capture-default" refers to [=] and [&]. To repeat, specifying a capture-default doesn't capture anything; only odr-using a variable does.

Solution 2 - C++

No! (thankfully)

You can instrument your code to check whether your compiler actually does it (or not). For example gcc 4.8.0 appears to be compliant.


As to what the Standard actually mandates (working backward):

> §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 &. For each entity captured by copy, an unnamed nonstatic data member is declared in the closure type. > > $5.1.2/11 If a lambda-expression has an associated capture-default and its compound-statement odr-uses (3.2) 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; such entities shall be declared within the reaching scope of the lambda expression. > > §5.1.2/9 A lambda-expression whose smallest enclosing scope is a block scope (3.3.3) is a local lambda expression; any other lambda-expression shall not have a capture-list in its lambda-introducer. The reaching scope of a local lambda expression is the set of enclosing scopes up to and including the innermost enclosing function and its parameters. [ Note: This reaching scope includes any intervening lambda-expressions. —end note ]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionArmen TsirunyanView Question on Stackoverflow
Solution 1 - C++Kerrek SBView Answer on Stackoverflow
Solution 2 - C++Matthieu M.View Answer on Stackoverflow