我正在学习 C++ lambda 函数。为什么它有这个输出?

I'm learning C++ lambda function. Why does it have this output?

这是我的代码

#include<iostream>
int* p = nullptr;
auto fun()
{
    int a = 1;
    p = &a;
    std::cout << &a << std::endl;
    auto z = [&a]() {std::cout << &a << "   "; a++; std::cout << "lambda call " << a << std::endl; };
    return z;
}
int main()
{
    auto z = fun();
    std::cout << *p << "\n";
    z();
    z();
    
    fun()();
}

输出为

0x7fffd10af15c
1
0x7fffd10af15c   lambda call 21880
0x7fffd10af15c   lambda call 21880
0x7fffd10af15c
0x7fffd10af15c   lambda call 21880

我的编译器版本是gcc 9.4.0版(Ubuntu9.4.0-1ubuntu1~20.04.1) 为什么我有这个输出?这是未定义的行为吗?

是的,问题是 afun 函数中的局部变量,在 fun 完成时被销毁。这意味着,返回的 lambda z 引用了堆栈上的一个区域,其中 a 曾经是,但现在当 z 被调用时,这个区域被用于其他用途(这就是为什么你参见 21880)。

为了避免这个问题,你需要防止 a 在离开 fun 的范围时被销毁。一种方法是将 a 声明为全局变量,就像 p 一样。另一种是让它成为静态变量。

Why do i have this output?

给定的程序有未定义的行为,因为a是一个局部变量,一旦函数returns就会被销毁,所以它(a) 不应再次引用。

Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior. The program may just crash.

所以您看到(也许看到)的输出是未定义行为的结果。正如我所说,不要依赖具有 UB 的程序的输出。程序可能会崩溃。

因此,使程序正确的第一步是删除 UB。 然后并且只有那时你可以开始对程序的输出进行推理。

要解决此问题,请确保您不会通过将局部变量(a)设为 staticglobal.[=18 来引用超出其范围的局部变量=]


1有关未定义行为的更技术准确的定义,请参阅 this 其中提到:没有对程序行为的限制.