I've seen in multiple examples that you can use a single character to capture multiple variables like the following:
Rect rect;
Point point;
auto someLambda = [&](const SomeType& var)
{
if (rect.Contains(point))
{
var.Something();
}
this->MemberFunction();
};
This ends up grabbing rect
and point
by reference and also gives you access to this
, but how much does it actually capture? Does it only capture the variables that it needs, or does it capture literally everything there is in the current scope?
I've seen in other examples that you can also specify individual variables to capture like this:
Rect rect;
Point point;
auto someLambda = [this, &rect, &point](const SomeType& var)
{
if (rect.Contains(point))
{
var.Something();
}
this->MemberFunction();
};
Is there any advantage to doing it one way or the other? Someone I worked with once mentioned that using the "capture all" [&]
version was more expensive but I can't find any documentation to back that up. I just want to know for sure so I'm not making code more complex than it needs to be or doing expensive things that I shouldn't be doing.
In C++11 and later, a lambda expression—often called a lambda—is a convenient way of defining an anonymous function object (a closure) right at the location where it's invoked or passed as an argument to a function.
By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them. In the following example, we capture the variable ammo and try to decrement it.
In Short. A lambda defined inside a non-static member function can directly access the members of the current object (or its copy) via an appropriate capture clause. But how the current object can be captured has gone through some changes since C++11.
A capture clause of lambda definition is used to specify which variables are captured and whether they are captured by reference or by value. An empty capture closure [ ], indicates that no variables are used by lambda which means it can only access variables that are local to it.
According to http://en.cppreference.com/w/cpp/language/lambda, the capture list (the part in the square braces) is:
a comma-separated list of zero or more captures, optionally beginning with a capture-default. Capture list can be passed as follows [...]:
[a,&b] where a is captured by value and b is captured by reference.
[this] captures the this pointer by value
[&] captures all automatic variables odr-used in the body of the lambda by reference
[=] captures all automatic variables odr-used in the body of the lambda by value
[] captures nothing
This means that only the automatic (scope-lifetime) variables used in the body of the lambda will be captured.
I can't see why capturing everything with [&]
would be more expensive than individual captures, but one advantage of listing out the captures explicitly is that there's no chance of capturing something you didn't expect.
On the other hand, capturing with [=]
could prove expensive since it will make copies of everything. Perhaps that's what your coworker was referring to.
This ends up grabbing rect and point by reference and also gives you access to this, but how much does it actually capture?
When you capture with [&]
it captures all the variables in the body of the lambda that have automatic storage duration and are odr-used.
Here is an example:
int main()
{
int num = 50;
[&] { std::cout << num << '\n'; }(); // num captured by reference
[=] { std::cout << num << '\n'; }(); // num captured by value
[&num] { std::cout << num << '\n'; }(); // by reference
[num] { std::cout << num << '\n'; }(); // by value
}
If you know that you will only capture one variable, you don't need to capture everything by value / reference.
But on the other hand, if you know that you will be capturing a few variables, capturing them with [&]
or [=]
is easier than typing them all out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With