这是我的代码
#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
)设置为static
或global
来引用超出其作用域的局部变量。
1对于未定义行为的更准确的技术定义,请参见这里提到的:对程序的行为没有限制。
是的,问题是a
是fun
函数中的局部变量,并且在fun
完成时被销毁。这意味着,返回的lambdaz
引用了堆栈上a
曾经所在的区域,但是现在当调用z
时,该区域被用于其他地方(这就是为什么你看到21880)。
为了避免这个问题,你需要防止a
在离开fun
的作用域时被破坏。一种方法是将a
声明为全局变量,就像p
一样。另一种方法是将其设置为静态变量。