I am trying to realize this piece of high-order function in python using C++:
def add1(x):
def helper():
nonlocal x
x += 1
return x
return helper
Here are the three versions I created:
#include <iostream>
#include <functional>
using namespace std;
function<int(void)> add1_v1(int x) {
function<int(void)> g = [&x]() {return ++x;};
return g;
}
auto add1_v2(int x) {
function<int(void)> g = [&x]() {return ++x;};
return g;
}
auto add1_v3(int x) {
auto g = [&x]() {return ++x;};
return g;
}
int main() {
auto a = add1_v1(100);
auto b = add1_v2(100);
auto c = add1_v3(100);
for(int i = 0; i < 3; ++i) {
cout << a() << endl;
}
cout << "-------------------------------------------" << endl;
for(int i = 0; i < 3; ++i) {
cout << b() << endl;
}
cout << "-------------------------------------------" << endl;
for(int i = 0; i < 3; ++i) {
cout << c() << endl;
}
return 0;
}
The outputs are:
101
102
103
-------------------------------------------
4239465
4239466
4239467
-------------------------------------------
4201325
4201325
4201325
Only add1_v1 matches what I want. Can anyone explain the reason for me?
Generic lambdas were introduced in C++14 . Simply, the closure type defined by the lambda expression will have a templated call operator rather than the regular, non-template call operator of C++11 's lambdas (of course, when auto appears at least once in the parameter list).
It is a convenient way to define an anonymous function object or functor. It is convenient because we can define it locally where we want to call it or pass it to a function as an argument. Lambda is easy to read too because we can keep everything in the same place.
A lambda can introduce new variables in its body (in C++14), and it can also access, or capture, variables from the surrounding scope. A lambda begins with the capture clause. It specifies which variables are captured, and whether the capture is by value or by reference.
A capture clause of lambda definition is used to specify which variables are captured and whether they are captured by reference or by value. An empty capture closure [ ], indicates that no variables are used by lambda which means it can only access variables that are local to it.
The reason is that this is undefined behavior.
The inner lambda captures x
by reference.
The problem is that as soon as add()
returns, its parameter gets destroyed, and the returned lambda has a dangling reference to a destroyed object.
The lambda must capture x
by value; and what it looks to me you're really trying to do here is a mutable lambda:
auto add(int x) {
function<int(void)> g = [x]() mutable {return ++x;};
return g;
}
Note that this approach carries certain implications when it comes to subsequently copying the returned lambda; but as long as the returned lambda remains "in one place", throughout its remaining lifetime, the resulting semantics will probably be what you expect.
All of them are ill-formed, because you're capturing x
by reference in lambda, but x
is a local variable and would be destroyed when get out of the function add
, then the reference becomes dangle, dereference on it latter causes UB, which means anything is possible; even the 1st case seems works fine.
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