如果通过lambda函数对象返回对局部变量的引用,会发生什么


#include <iostream>
auto get_lambda()
{
int i = 5;
auto lambda = [&i]() { std::cout << i << 'n'; };
return lambda;
}
int main()
{
auto lambda = get_lambda();
lambda();
}

在"get_lambda"函数中,我定义了局部变量"I"。然后,该函数返回lambda对象,该对象具有对该局部变量的一个捕获引用。在"main"内部,我调用那个lambda,结果"I"是未初始化的内存。

变量"i"位于get_lambda的堆栈上。当函数返回时,此堆栈不再有效。

为什么这段代码要编译,变量"i"到底发生了什么,它在get_lambda之外仍然可用吗?

在您的案例中,您正在调用未定义的行为。i名称是get_lambda()函数的本地名称,一旦i超出作用域,它就会被销毁。因此,使用lambda,您现在存储的是对已经不存在的东西的引用。这也被称为悬挂引用。按值捕获本地变量:

auto lambda = [i]() { std::cout << i << 'n'; };

或:

auto lambda = [=]() { std::cout << i << 'n'; };

实际上,您可以通过lambda的捕获列表中的引用来捕获本地变量。因此,没有编译器错误。根据编译器的不同,可能会发出警告。

i仅在其作用域中可用,该作用域位于get_lambda()内部。显然,它在其作用域之外是不可用的,这正是您稍后调用lambda()时所尝试的。

就像使用悬挂指针一样,这是未定义的行为。同样,编译器会让你"使用"这样一个指针,但作为程序员,你有责任知道你违反了规则。

相关内容

最新更新