void.pointer
void.pointer

Reputation: 26335

When to prefer explicit capture in lambda over implicit captures?

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?

Upvotes: 12

Views: 5454

Answers (2)

paceholder
paceholder

Reputation: 1104

  • Explicit capture is always preferable as it is less error-prone
  • It is better to use & in case of heavy objects (not simple int, double etc)
  • Use = when you plan to use your lambda outside the scope of the variable capturing. With & it is risky to get dangling reference to the local destroyed variable

Upvotes: 8

M.M
M.M

Reputation: 141554

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:

  • You forget to capture something that the lambda uses
  • You capture something that the lambda didn't need.

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.

Upvotes: 5

Related Questions