0

Consider the following code:

int foo() {
    int lf = [/*captures*/]() {/*body*/};
    if(/*some condition*/) { return /*value*/; }
    foo();    //recursive call
}

Now, in this code, whenever the function foo is called recursively, an activation record of foo will be pushed on to the stack. What I was wondering about is that, is the lambda function included in the record with its definition? Umm..this ain't helping

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185

2 Answers2

2

The lambda is stored in a local variable of foo(), so yes. Each call to foo() instantiates a new lambda that is not destroyed until foo() exits.

A lambda is just syntax sugar for a compiler-defined type that implements operator(). So your example is roughly equivalent to this:

struct functor{
    /*captures*/
    void operator()() const {/*body*/}
};

int foo() {
    functor lf{/*captures*/};
    if(/*some condition*/) { return /*value*/; }
    foo(); //recursive call
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    From what I know, it is a bit compiler defined too. Some compilers create a copy of the lambda function in a different location, simply call it using the address and only add the variables into the activation record. – kesarling He-Him Mar 25 '20 at 07:59
  • @d4rk4ng31 tit's a function. function is not an object by C++ definition, so compiler\program can't really generate new instructions in memory each time, and what happens is what falls under definition for creation of new automatic storage belonging to a callable object. Now lambda expression creates NOT function, but an object of unique type, its uniqueness defined by context it was created in. Regardless how many times recursion had happen it is same context,unless it's a recursive template. – Swift - Friday Pie Mar 30 '20 at 11:01
  • @d4rk4ng31 Then it's possible that each instance of template could own lambda created in compile time, but in fact it's just instance of a new `operator()` - generic lambda's case. – Swift - Friday Pie Mar 30 '20 at 11:05
1

Firstly:

int lf = [/*captures*/]() {/*body*/};

is incorrect code, it should be

// case 1. lambda is automatic
auto lf = [/*captures*/]() {/*body*/}; // closure object

or (provided that lambda returns something compatible to int)

// case 2. lambda is temporary
int lf = [/*captures*/]() {/*body*/} (); /* calling object created */

lambda expression is a shorthand notation for creation of object with a unique class (very simplified, you have to look in standard or in language reference for full description):

class Closure {
    /* members storing captured values or references */ 
public:
    return-type  operator( /* argument list*/ ) { /*body*/ };
}

In first case lambda would be stored in stack, in second case it is a temporary object.

So lambda with a capture list would store such object, i.e. all captured values exactly where you instructed it to store lambda object, in your case it's automatic storage (so called, "stack"). Using a capture-less lambda is no different from declaring a function and using a pointer to it, there is no storage associated with it and it can be casted to a function pointer.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42