Я боролся с проблемой с лямбда-выражениями, которая ставила под угрозу мой проект. Я нашел решение, но я хотел бы точно понять, как и почему он работает, и если он надежный.
#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;
}
Я знаю, что это сумасшедший способ вычислить 20-й номер Фибоначчи, но это самый компактный SSCCE, который я смог разработать.
Если я скомпилирую код выше с помощью g++ -O0
, и я запускаю программу, я получаю 6765
, что на самом деле является 20-м числом Фибоначчи. Если я скомпилирован с -O1
, -O2
или -O3
, я получаю 262144
, что является мусором.
Если я профилирую программу с помощью Valgrind (компиляция с -O0 -g
), я получаю Conditional jump or move depends on uninitialised value(s)
в строке std::cout << f(20, callback) << std::endl;
, но трассировка стека не говорит ничего полезного.
Я не знаю, почему я закончил с этим:
Callback callback = [&](const int& i) -> const int& {
С помощью этой небольшой модификации все работает как ожидается, компилируется с любым уровнем оптимизации, и Valgrind не сообщает о проблемах.
Можете ли вы помочь мне понять, что происходит?