Внутренняя работа лямбда-функций, когда функция-обертка вызывается рекурсивно - PullRequest
1 голос
/ 25 марта 2020

Рассмотрим следующий код:

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

Теперь в этом коде всякий раз, когда функция foo вызывается рекурсивно, activation record из foo будет помещаться в стек. Что меня интересует, так это то, включена ли лямбда-функция в запись с ее определением? Эмм .. это не помогает

Ответы [ 2 ]

2 голосов
/ 25 марта 2020

Во-первых:

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

- неверный код, он должен быть

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

или (при условии, что лямбда возвращает что-то, совместимое с int)

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

лямбда-выражение - это сокращенное обозначение для создания объекта с уникальным классом (очень упрощенное, вы должны посмотреть стандартную или языковую ссылку для полного описания):

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

В первом случае лямбда будет хранится в стеке, во втором случае это временный объект.

Таким образом, лямбда со списком захвата будет хранить такой объект, то есть все захваченные значения именно там, где вы указали ему хранить лямбда-объект, в вашем случае это автомат c хранилище (так называемый, «стек»). Использование лямбды без захвата ничем не отличается от объявления функции и использования указателя на нее, с ней не связано хранилище, и ее можно привести к указателю на функцию.

2 голосов
/ 25 марта 2020

Лямбда хранится в локальной переменной foo(), так что да. Каждый вызов foo() создает новую лямбду, которая не уничтожается до тех пор, пока не завершится foo().

Лямбда - это просто синтаксический сахар для типа, определенного компилятором, который реализует operator(). Итак, ваш пример примерно эквивалентен этому:

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

int foo() {
    functor lf{/*captures*/};
    if(/*some condition*/) { return /*value*/; }
    foo(); //recursive call
}
...