24

I just started learning lambda functions in C++ and i don't understand why lambda's allow capturing only automatic storage variables? For example:

int x;
int main() {
    [&x](int n){x = n;}; // 'x' cannot be captured...
    return 0;
}

On the other hand static variables don't need capturing at all

static int s = 0;
[](int n){s = n;};

So, why the first example is not allowed and the second works?

Tracer
  • 2,544
  • 2
  • 23
  • 58
  • 4
    It's not about the static qualifier as much as it it is about the scope of the variable http://ideone.com/2qVDaX Since the global will be visible in the lambda regardless, a capture is redundant. – StoryTeller - Unslander Monica Jun 29 '14 at 09:58
  • possible duplicate of [Can a C++11 lambda capture a file scope variable?](http://stackoverflow.com/questions/20361865/can-a-c11-lambda-capture-a-file-scope-variable) – Pradhan Jun 29 '14 at 09:59
  • 3
    I think it's interesting that you compare these two examples as though they're behaving differently. If you make the first one not try to capture `x` (as in the second one), it works. – Joseph Mansfield Jun 29 '14 at 10:03
  • Yes. I see. But, are those captured by reference or by copy? – Tracer Jun 29 '14 at 10:04
  • 1
    If you remove the `&x` it doesn't capture at all; it uses a global variable just like any other function. – Simple Jun 29 '14 at 10:06

2 Answers2

27

You need to go back and ask yourself: Why do lambdas capture variables at all?

Lambdas can use variables from an outer scope. However, if those are local variables, they go out of scope and cannot be used after the function returns. But a lambda could potentially be called after the function returns (the lambda could be returned from the function, or stored in some global or instance variable, etc.), and after the function returns, it cannot just refer to the local variables directly, because they no longer exist.

That's why lambdas can capture local variables by copy (copy their value at the time the lambda is created). (They can also capture by reference, as an alternative to by copy.)

The above issue only exists for variables of automatic storage duration. For variables of static storage duration (e.g. global variables, static local variables), they live for the lifetime of the program, and there is no problem with accessing them at any time.

newacct
  • 119,665
  • 29
  • 163
  • 224
  • 1
    Firstly thanks you for your nice insight! What happen when a local variable inside a function is captured by reference by a lambda which is invoked outside that scope? – Maf Jun 16 '21 at 09:57
  • 2
    @Maf: Then it is undefined behavior. It's the same as storing a reference to a local variable and trying to use that reference after the local variable's scope ends. – newacct Jun 16 '21 at 16:10
  • That makes sense. Thanks! – Maf Jun 16 '21 at 16:15
19

You need to change scope. Look at this:

int x = 4;

int main()
{
    cout << "::x = " << ::x << endl;

    [&](int a){ ::x = a; }(2);

    cout << "::x = " << ::x << endl;

    return 0;
}

Output:

::x = 4
::x = 2
Dakorn
  • 883
  • 6
  • 11
  • yes. I've seen it. But why do I need to specify the names of auto-storage variables in capture [] and not the global ones? Why simply not to use auto-storage variables as global variables (without capturing)? – Tracer Jun 29 '14 at 10:42
  • Lambdas are some kind of functions. In functions you have access to global variables, and lambdas have it too. Local variables, for example in `main()`, are not global ones, so you have to directly point these extern variables which you want to use. Maybe it helps you. – Dakorn Jun 29 '14 at 11:25
  • And why do we need to capture a variable which is global to `main()` inside a lambda which is inside `main()`? – Maf Jun 16 '21 at 09:31
  • @newacct's answer responds my question when h says "But a lambda could potentially be called after the function returns (the lambda could be returned from the function, or stored in some global or instance variable, etc.)". Thank you all for the good insights! – Maf Jun 16 '21 at 10:00