This question comes from Can lambda functions be recursive? . The accepted answer says the recursive lambda function shown below works.
std::function<int (int)> factorial = [&] (int i)
{
return (i == 1) ? 1 : i * factorial(i - 1);
};
However, it is pointed out by a comment that
such a function cannot be returned safely
, and the reason is supplied in this comment:
returning it destroys the local variable, and the function has a reference to that local variable.
I don't understand the reason. As far as I know, capturing variables is equivalent to retaining them as data members (by-value or by-reference according to the capture list). So what is "local variable" in this context? Also, the code below compiles and works correctly even with -Wall -Wextra -std=c++11
option on g++
7.4.0.
#include <iostream>
#include <functional>
int main() {
std::function<int (int)> factorial = [&factorial] (int i)
{
return (i == 1) ? 1 : i * factorial(i - 1);
};
std::cout << factorial(5) << "\n";
}
Why is the function unsafe? Is this problem limited to this function, or lambda expression as a whole?
You may not realise that you can write AWS Lambda functions in a recursive manner to perform long-running tasks. Here's two tips to help you do it right. AWS Lambda limits the maximum execution time of a single invocation to 5 minutes.
A recursive lambda expression is the process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. Using a recursive algorithm, certain problems can be solved quite easily.
If you trigger a recursive invocation loop accidentally, you can press the “Throttle” button in the Lambda console to scale the function concurrency down to zero and break the recursion cycle.
The recipe is simple: If you want to call a lambda recursively, just add an auto&& parameter taking the function again and call that. This produces basically optimal assembly and can be used in combination with capturing.
This is because in order to be recursive, it uses type erasure and captures the type erased container by reference.
This has the effect of allowing to use the lambda inside itself, by refering to it indirectly using the std::function
.
However, for it to work, it must capture the std::function
by reference, and that object has automatic storage duration.
Your lambda contains a reference to a local std::function
. Even if you return the std::function
by copy, the lambda will still refer to the old one, that died.
To make a secure to return recursive lambda, you can send the lambda to itself in an auto
parameter and wrap that in another lambda:
auto factorial = [](auto self, int i) -> int {
return (i == 1) ? 1 : i * self(self, i - 1);
};
return [factorial](int i) { return factorial(factorial, i); };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With