Background
I'm trying to pass a std::function
object as a parameter to evaluate
the sum of its returned value over a range.
However, for some reason, the function depends on a functor, Bar
, whose state depends on a parameter, a
.
My approach was to create a lambda
inside a curried function, foo
and ask it to capture a functor allocated by new
.
However, I found that after I passed the function created by foo
into evaluate
the address of the functor changed and the program did some crazy things.
Example
Here's a simplified reproducible example,
#include <iostream>
#include <functional>
using namespace std;
double evaluate(const function<double (const double &)> foo) {
double result = 0.0;
for (double i=0; i<1; ++i) {
result += foo(i);
}
return result;
}
struct Bar {
double a;
explicit Bar(const double &a): a(a) {}
double operator()(const double &b) const {
return b * a;
}
};
function<double(const double &)> foo(const double &a) {
auto bar = new Bar(a);
function<double (const double &)> result = [&](const double &b) {
cout << "address of bar: " << bar << endl;
return (*bar)(b);
};
return result;
}
int main() {
auto f = foo(1);
auto v = f(2);
cout << "value of f(2): " << v << endl;
v = evaluate(f);
cout << "evaluate(f): " << v << endl;
return 0;
}
A possible output of the above code could be
address of bar: 0x7ff7b787c870
value of f(2): 4.3834e-314
address of bar: 0x7ff7b787c840
evaluate(f): 0
Questions
Can anyone
evaluate
function)You are in UB world. Because bar
is a local variable here which is captured by reference:
function<double(const double &)> foo(const double &a) {
auto bar = new Bar(a);
function<double (const double &)> result = [&](const double &b) {
cout << "address of bar: " << bar << endl;
return (*bar)(b);
};
return result;
}
And you want to access it in other places assuming it exists. You should have already noticed a problem in your code from this result:
value of f(2): 4.3834e-314
Because it should be 2
. If you write code as follows:
function<double(const double &)> foo(const double &a) {
function<double (const double &)> result = [bar = new Bar(a)](const double &b) {
cout << "address of bar: " << bar << endl;
return (*bar)(b);
};
return result;
}
It will work as you expect. Just remember to use std::unique_ptr
rather than raw pointer here. This code, as it is right now, has a memory leak as a result of forgetting to release memory.