5

I just wrote a pretty big capture:

[this, &newIndex, &indexedDirs, &filters, &flags, &indexRecursion](){...

I use this lambda (indexRecursion) for a recursion with thoudands of elements and asked myself, if it would be more efficient to use the "global" capture [&]. Since I have no clue of the implementation of the capture I need some explanation. Please with background too.

ManuelSchneid3r
  • 15,850
  • 12
  • 65
  • 103
  • 6
    implementation defined. there is no correct answer. if performance is a problem, rethink the algorithm. – Richard Hodges Oct 01 '15 at 22:57
  • 1
    `&` probably has the same effect as explicitly capturing everything that you actually use, so it won't be faster. – Brian Bi Oct 01 '15 at 23:11
  • Note that with the global capture `[&]`, you will capture `this` by reference and potentially introduces an other indirection. – Jarod42 Oct 01 '15 at 23:19
  • [Does the C++ standard force capturw-by-reference of local variables to be inefficient?](http://stackoverflow.com/q/31318762/1708801) is probably relevant. – Shafik Yaghmour Oct 02 '15 at 00:18

2 Answers2

8

Usually you can think of a lambda as equivalent to this:

class ANON {
  int data;
  public:
    void operator ()(void) const {
      cout << data << endl;
    }
} lambda;
// auto lambda = [data]() {cout << data << endl;}

This should give you an idea of how capture is implemented. Capture all (be it by copy = or reference &) will probably be no more than syntactic sugar for specifying all used/available variables for capture in the current scope.

But since ...

[..] An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing: [..] the size and/or alignment of the closure type [..]

[N4431 §5.1.2/3]

... it would be legal for an implementation to use some sort of "black magic" for capture all by reference lambdas and just use a pointer to the captured stack frame, rewriting accesses to the variables as accesses to some offset of that pointer:

class ANON {
  void * stack_frame;
  public:
    void operator ()(void) const {
      cout << *static_cast<int *>(stack_frame + 8) << endl;
    }
} lambda;

So using & might (some day) be more efficient, but as already said this is implementation defined and this nothing to be relied upon.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
2

Internally lambdas are /usually/ implemented as ad-hoc classes whose single instance object is constructed in the point of lambda definition and which are exposing a functor to be called later. So lambda performance should be compared with passing a method to a function using std::bind.

Captures aren't mystical entities as well. If captures are reference-captures, entities which they refer to are detroyed when go out of the scope as usual, so beware if your lambda isn't local: inside its body it may refer to object which have been destroyed already.

user3159253
  • 16,836
  • 3
  • 30
  • 56
  • Just a note. To avoid the deletion of a captured variable, define it as a `shared_ptr` and inherit from `std::enable_shared_from_this`. – JMRC May 20 '21 at 00:01