为什么通过引用捕获 lambda 仍在使用悬空引用?

Why does lambda capture by reference is still working with dangling references?

令我惊讶的是,以下 C++ 程序:

#include <iostream>
#include <functional>


int main() {
    std::function<void(void)> f;
    {
        int x = 1;
        f = [&x]() { std::cout << x; };
    }
    //std::cout << x;  // error: use of undeclared identifier 'x'
    f();               // no error!
    return 0;
}

输出:

1

我期望的输出与取消注释注释行时得到的输出相同:

error: use of undeclared identifier 'x'

因为 lambda f 通过引用(而不是 通过值)捕获了自动变量 x 并且x 在调用 f() 时不在上下文中(因此 f 正文中的 x 是悬空引用)。

为什么通过引用捕获的 lambda 仍然适用于悬挂引用?

它不起作用。这只是它显示 1 的巧合。只是在调用 lambda 时驻留在捕获的地址中的某些值包含可以解释为值为 1 的 int 类型的值。

lambda 的生命周期大于变量的生命周期。变量 x 在右花括号处被销毁,但 lambda 仍然持有对它的引用。任何访问该引用的尝试都会导致未定义的行为。

在 lambda 声明中,您告诉 要捕获什么。使用声明的地方的当前范围。在调用 lambda 时,您告诉 何时 捕获。这就是为什么它与您问题中的引用相比进行编译的原因。但您有责任提供所用变量的正确生命周期。

Why does lambda capture by reference is still working with dangling references?

这是未定义的行为,因此可能有任何原因可以解释为什么它会以这种方式工作。如果您使用以下代码编译代码:

在这里试试:https://godbolt.org/z/5dd5sM

clang++ -O3 -fsanitize=address

您将立即获得:

ERROR: AddressSanitizer: stack-use-after-scope on address ....
READ of size 4...