0

令我惊讶的是,以下 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通过引用(而不是通过 valuef捕获自动变量,并且在调用点不在上下文中(所以在body 中是一个悬空引用)。x xf()xf

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

4

2 回答 2

1

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

这是未定义的行为,因此可以有任何理由说明为什么它以它的工作方式工作。如果您使用以下代码编译代码:

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

clang++ -O3 -fsanitize=address

您将立即获得:

ERROR: AddressSanitizer: stack-use-after-scope on address ....
READ of size 4...
于 2020-08-11T10:57:44.467 回答
1

它不工作。这只是一个巧合,它显示为 1。只是在调用 lambda 时驻留在捕获的地址中的东西保存了可以解释为值为 1 的 int 类型的值。

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

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

于 2020-08-11T10:44:10.273 回答