SwiftMango
SwiftMango

Reputation: 15304

What is the purpose of specifying captured variable in lambda expression?

I have this code:

int i = 0;
[&i](){i++;}();

But I can omit i and just use:

[&](){i++;}();

What is the purpose of specifying &i? (and similarly =var and =). Is it affecting compile time or runtime performance?

Upvotes: 29

Views: 1525

Answers (5)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361792

&i means only i is captured as reference, while & means all variables which are used in the lambda, are captured from the scope.

int i = 0, j = 10;

[&i]{ i++; j++;}(); //error: j is not captured by reference

[&]{ i++; j++;}(); //ok: both variables are captured by reference

The &i approach is provided by the language to limit the amount of captured variables. C++ provides you full control on the captured variables, as to which specific variables to capture, how to capture (by value, or reference).

Same reasoning with i and =:

int i = 0, j = 10;

[i]{ i++; j++;}(); //error: j is not captured (only i is captured by value)

[=]{ i++; j++;}(); //ok: both variables are captured by value

//more
[&i, j]{ i++; j++;}(); //ok: captured i by reference, j by value

Hope that helps.

Upvotes: 26

Timothy Shields
Timothy Shields

Reputation: 79621

Sometimes you may want to capture different variables in different ways:

std::vector<int> v { 7, 8, 9, 10, 11 };
int n = 3;

//Capture v by reference and n by value:
auto getNth = [&v, n](){ return v[n]; };

//Behavior:
n = 9999;
getNth(); //returns 10 - changing n didn't affect the lambda
v[3] = 42;
getNth(); //returns 42 - changing v did affect the lambda

This is why the more-detailed syntax is available.

Upvotes: 22

If you list the variables to capture, you're being explicit in what you want. And you get a compiler error in case you use something you didn't want to (you didn't capture it). This may be a good thing (you made a genuine mistake in the implementation) or a bad thing (you just forgot to list the variable).

It really depends on the particular scenario. I'd that the more complex the lambda and/or the more complex the containing scope, the better it is to be explicit about what you capture.

There's an extra point, and that is mixing capture by value and capture by reference - you have to be explicit in at least one of those. Example:

int i, j, k;

auto f = [=, &i]() { /* code which can read i, j and k but can only modify i */ };

Upvotes: 4

Reed Copsey
Reed Copsey

Reputation: 564891

What is the purpose of specifying &i? (and similarly =var and =). Is it affecting compile time or runtime performance?

You can specify whether values are captured by reference or by value. Using [&] specifies that you want to capture everything by reference, but you can also write lambda which does:

[=, &i, &j]()

Which says capture everything by value, except capture i and j by reference.

In your specific case, this isn't useful - you can just say capture everything by reference, and the compiler will determine that you're using i, and capture it by reference - but when you deal with multiple variables being captured, C++ allows you to control how each is captured individually.

Upvotes: 11

JaredPar
JaredPar

Reputation: 755557

This feature isn't about performance it's about readability and maintainability. When you use the blanket capture syntax [&] or [=] then it obscures the state which is shared between the original method and the lambda body. This can contribute to maintenance issues in a method if a dev incorrectly assumes a value isn't captured and it is. Having a capture clause makes it much more explicit what state the lambda relies on.

Upvotes: 18

Related Questions