11

私は自分のプロジェクトを危険にさらしていたラムダ式の問題に取り組んできました。解決策を見つけましたが、それがどのように、なぜ機能するのか、信頼できるかどうかを正確に理解したいと思います。

#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、これはゴミです。

-O0 -gValgrind (でコンパイル) でプログラムをプロファイリングすると、問題は解決しConditional jump or move depends on uninitialised value(s)ますstd::cout << f(20, callback) << std::endl;が、スタック トレースには有用な情報が何も表示されません。

なぜ私はこれで終わったのかわかりません:

Callback callback = [&](const int& i) -> const int& {

この少しの変更により、あらゆる最適化レベルでのコンパイルですべてが期待どおりに機能し、Valgrind は問題を報告しません。

何が起こっているのか理解するのを手伝ってもらえますか?

4

2 に答える 2