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



这是我的代码

#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 (Ubuntu 9.4.0-1ubuntu1~20.04.1)为什么我有这个输出?这是一个未定义的行为吗?

为什么我有这个输出?

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

未定义行为意味着任何1都可能发生,包括但不限于给出预期输出的程序。但是从不依赖(或基于)具有未定义行为的程序的输出。程序可能会崩溃。

所以你看到的输出(可能看到的)是未定义行为的结果。正如我所说的不要依赖于输出一个有UB的项目程序可能会崩溃。

因此,使程序正确的第一步是删除UB。当且仅当你可以开始对程序的输出进行推理。

要解决这个问题,请确保您不会通过将它们(a)设置为staticglobal来引用超出其作用域的局部变量。


1对于未定义行为的更准确的技术定义,请参见这里提到的:对程序的行为没有限制

是的,问题是afun函数中的局部变量,并且在fun完成时被销毁。这意味着,返回的lambdaz引用了堆栈上a曾经所在的区域,但是现在当调用z时,该区域被用于其他地方(这就是为什么你看到21880)。

为了避免这个问题,你需要防止a在离开fun的作用域时被破坏。一种方法是将a声明为全局变量,就像p一样。另一种方法是将其设置为静态变量。

最新更新