There are sometimes cases where I do a std::find_if
(for example) in a local function that has 5 local variables, including parameters. However, the lambda I pass into the STL algorithm only needs access to 1 of those. I could capture this in one of two ways:
void foo(int one, int two, int three)
{
std::vector<int> m_numbers;
int four, five;
std::find_if(m_numbers.begin(), m_numbers.end(), [=](int number) {
return number == four;
});
}
Or I can do:
void foo(int one, int two, int three)
{
std::vector<int> m_numbers;
int four, five;
std::find_if(m_numbers.begin(), m_numbers.end(), [four](int number) {
return number == four;
});
}
(Note I didn't compile this code, apologies for any syntax errors or other mistakes)
I know that implicit captures are based on odr-used rules, so functionally and implementation-wise, I think both are identical. When would you use explicit captures over implicit ones? My only thought is somewhat related to principles of encapsulation: Having access to only the stuff you need allows the compiler to help you determine when you access a variable you shouldn't. It also keeps the local state of the method (it's invariants, for the lifetime of the function during its execution) safer. But are these really practical concerns?
Are there functional reasons to use explicit captures over implicit ones? What is a good rule of thumb or best practice to follow?
Any entity captured by a lambda (implicitly or explicitly) is odr-used by the lambda-expression (therefore, implicit capture by a nested lambda triggers implicit capture in the enclosing lambda). All implicitly-captured variables must be declared within the reaching scope of the lambda.
Lambda capture. The captures is a comma-separated list of zero or more captures, optionally beginning with the capture-default. The only capture defaults are. & (implicitly capture the used automatic variables by reference) and. = (implicitly capture the used automatic variables by copy).
A lambda expression can use a variable without capturing it if the variable is a non-local variable or has static or thread local storage duration (in which case the variable cannot be captured), or is a reference that has been initialized with a constant expression.
The capture list defines the outside variables that are accessible from within the lambda function body. The only capture defaults are = (implicitly capture the used automatic variables by copy).
It is simplest and the most efficient at runtime to use [=]
or [&]
, without naming any names.
In these cases, as described by this answer, variables are only captured if they are odr-used. In other words the compiler only captures what is needed.
If you specify a capture list then two differences can happen:
In the second case, if capturing by value, this means the object is unnecessarily copied.
So, my advice would be to use []
, [&]
, or [=]
unless you can think of a good reason otherwise for a specific situation. One such case might be if you wanted to capture some variables by reference and some by value.
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