32
std::function<int()> void f1()
{
    int a, b, c, d, ..., x, y, z;

    return [=] { return a + b + c; };
}

vs.

std::function<int()> void f2()
{
    int a, b, c, d, ..., x, y, z;

    return [a, b, c] { return a + b + c; };
}

Needless to say, the former is shorter, handier, and more elegant than the latter.

However, I still worry:

From the performance viewpoint, is the latter always better than the former?

Does the standard guarantee a lambda expression captures the necessary variables only? i.e. In the former example, only a, b, c are captured, the unused variables d, ..., x, y, z are not.

newacct
  • 119,665
  • 29
  • 163
  • 224
xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 3
    They only capture what is used. Style trumps performance by a long shot here. – chris Sep 26 '13 at 02:00
  • @chris, could you refer me to the standard? – xmllmx Sep 26 '13 at 02:01
  • 3
    @xmllmx I can't refer you to a paragraph, but consider a class that has a copy constructor with side effects (a file write, cout, etc). If a lambda captured an unused, unlisted object of that type by value and so invoked the copy constructor, that would be *pretty bad*. So even without seeing the 'law' on this, I'd say this is pretty certain. – us2012 Sep 26 '13 at 02:03
  • +1. @us2012, How about `return [=a, =b, =c, =d] { return a + b + c; };`? d is explicitly declared to be captured, but it is not used, what will happen? – xmllmx Sep 26 '13 at 02:07
  • 3
    5.1.2 p11: "If a lambda-expression has an associated capture-default and its compound-statement odr-uses (3.2) this or a variable with automatic storage duration and the odr-used entity is not explicitly captured, then the odr-used entity is said to be implicitly captured." So the variable must be odr-used in the lambda. It's possible that an odr-used variable is not used, but you'd be better off removing the reference to unused variables than explicitly listing the used ones. – rici Sep 26 '13 at 02:07
  • 1
    @rici That should really be an answer. – us2012 Sep 26 '13 at 02:09
  • @chris I don't think that that question is a useful duplicate. I voted to leave this one open. – Walter Oct 01 '13 at 07:57

3 Answers3

50

Performance

The standard guarantees that if you do a default capture, the only variables that will be captured by that default capture from the surrounding environment are those that you actually use inside the lambda.

As such, specifying individual variables to capture acts as documentation of what you expect to use, but should never affect performance.

For anybody who cares, the exact wording from the standard is (§5.1.2/11, 12):

11 If a lambda-expression has an associated capture-default and its compound-statement odr-uses (3.2) this or a variable with automatic storage duration and the odr-used entity is not explicitly captured, then the odr-used entity is said to be implicitly captured; such entities shall be declared within the reaching scope of the lambda expression. [Note elided]

12 An entity is captured if it is captured explicitly or implicitly. [...]

Readability

Opinions seems split on this point. Some people like the documentation of intent that comes with explicitly specifying what you capture. Others see this as visual noise that mostly gets in the way of understanding what the lambda is/does.

Personally, I think it's usually kind of irrelevant--most lambadas are (and should be) quite small and simple, and only need to capture a few things. As such, explicit documentation of what they capture doesn't add much noise, but also doesn't add much to making the code more understandable. If explicit capture makes a huge difference in either direction, that may hint at there being other problems with the code.

Summary

An implicit capture specification ([=] or [&]) will only capture variables that are used in the lambda, so implicit vs. explicit capture should never affect performance.

I don't think there's a simple, clear answer with respect to readability.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    Meaning capture all by [&] is not a bad thing in respect of performance and readability. – jtony Dec 23 '19 at 15:11
4

Not really... most other languages don't require (or even allow) you to specify what you want to capture either.

Let the compiler infer what's necessary when it can.
It won't make a mistake, and it won't "accidentally" capture something unused inside the lambda.
If you want to be explicit (sometimes that makes sense), that's what traditional functors are perfect for.

user541686
  • 205,094
  • 128
  • 528
  • 886
1

Semantically, you should only be importing those variables you actually need into the scope of your lambda. For anything other than built-in types you're also likely to want capture by reference as well.

David G
  • 5,408
  • 1
  • 23
  • 19
  • 1
    If the lambda expression is a result to return, capturing variables by reference is a bad practice in most cases. – xmllmx Sep 26 '13 at 02:13
  • @xmllmx: I don't know what aspect of this answer you're trying to correct... it's not just "bad practice" to do that when the lambda is being returned; it's plain wrong. In which case it should be pretty obviously you shouldn't capture it by reference, since the code won't work. The advice given in this answer is pretty on the mark.. "capture by reference when possible". – user541686 Sep 26 '13 at 02:22
  • @Mehrdad, if a lambda expression references a static variable, it is not wrong, even if it is a result to return. – xmllmx Sep 26 '13 at 03:21
  • 1
    @xmllmx you don't need to capture `static` variables. – Simple Sep 26 '13 at 07:21
  • +1. @Simple, Yes. It should be as is. Thanks. – xmllmx Sep 26 '13 at 09:06