Strange undefined behaviour with tricky lambda expression
I've been struggling against a problem with lambda expressions that was
jeopardizing a project of mine. I have found a solution, but I would like
to understand exactly how and why it works, and if it is reliable.
#include <iostream>
#include <functional>
#include <unordered_map>
typedef std::function<const int&(const int&)> Callback;
int f(int i, Callback callback) {
if (i <= 2) return 1;
return callback(i-1) + callback(i-2);
}
int main(void) {
std::unordered_map<int, int> values;
Callback callback = [&](const int& i) {
if (values.find(i) == values.end()) {
int v = f(i, callback);
values.emplace(i, v);
}
return values.at(i);
};
std::cout << f(20, callback) << std::endl;
return 0;
}
I know this is a crazy way to compute the 20th Fibonacci number, but it is
the most compact SSCCE I was able to elaborate.
If I compile the code above with g++ -O0 and I execute the program, I get
6765, which is actually the 20th Fibonacci number. If I compile with -O1,
-O2 or -O3 I get 262144, which is rubbish.
If I profile the program with Valgrind (compiling with -O0 -g), I get
Conditional jump or move depends on uninitialised value(s) on the line
std::cout << f(20, callback) << std::endl; but the stack trace doesn't
tell anything useful.
I don't know why I ended up with this:
Callback callback = [&](const int& i) -> const int& {
With this little modification, everything works as expected compiling with
any optimization level, and Valgrind reports no issues.
Can you help me understand what's going on?
No comments:
Post a Comment