弄清楚为什么在嵌套的 lambda 中通过引用捕获会产生奇怪的结果

Figuring out why capturing by reference in a nested lambda produces a weird result

外层变量x被值捕获时

return [=](int y){ return x * y; };

foo(2)(3) 产生 6.

但是,如果我通过引用捕获 x

return [&](int y){ return x * y; };

foo(2)(3) 产生 9.

最小代码

#include <iostream>
#include <functional>

int main()
{
    using namespace std;
    function<function<int(int)>(int)> foo = [](int x)
    {
        return [&](int y) { return x * y; };
    };
    cout << foo(2)(3);
    return 0;
}

问题

我不明白为什么会这样,你能吗?

当 lambda 通过引用捕获 x 时,当 foo(2) 的调用结束时,参数 x 被销毁,然后捕获到它的引用变为悬挂。在 foo(2)(3) 的调用中取消引用会导致 UB,一切皆有可能。

按值捕获不存在此类无效引用问题。

x 是外部函数的本地函数,因此它会在该函数 returns.

后立即被销毁

考虑一个更简单的例子。

#include <iostream>
#include <functional>

int& foo(int x) {
    return x;
}

int main()
{
    using namespace std;
    int& b = foo(5);
    return 0;
}

这里更容易看出 b 是悬空引用。

接下来我们继续,我们 return 一个通过引用捕获变量的 lambda,而不是直接 return 引用。

#include <iostream>
#include <functional>

auto foo(int x) {
    return [&x]() {return x;};
}

int main()
{
    using namespace std;
    auto b = foo(5);
    return 0;
}

问题依旧。一旦 lambda 被 returned,x 已经超出范围并且不再存在。但是 lambda 持有对它的(悬空)引用。