c++ - 为什么这个递归 lambda 函数不安全?
问题描述
这个问题来自Can lambda functions be recursive? . 接受的答案说下面显示的递归 lambda 函数有效。
std::function<int (int)> factorial = [&] (int i)
{
return (i == 1) ? 1 : i * factorial(i - 1);
};
但是,有评论指出,
这样的函数不能安全返回
,原因在此评论中提供:
返回它会破坏局部变量,并且该函数具有对该局部变量的引用。
我不明白原因。据我所知,捕获变量相当于将它们保留为数据成员(根据捕获列表按值或按引用)。那么在这种情况下什么是“局部变量”?此外,即使使用7.4.0上的-Wall -Wextra -std=c++11
选项,下面的代码也可以编译并正常工作。g++
#include <iostream>
#include <functional>
int main() {
std::function<int (int)> factorial = [&factorial] (int i)
{
return (i == 1) ? 1 : i * factorial(i - 1);
};
std::cout << factorial(5) << "\n";
}
为什么函数不安全?这个问题仅限于这个函数,还是整个 lambda 表达式?
解决方案
这是因为为了递归,它使用类型擦除并通过引用捕获类型擦除的容器。
这具有允许在其内部使用 lambda 的效果,通过使用std::function
.
但是,要使其工作,它必须捕获std::function
引用,并且该对象具有自动存储持续时间。
您的 lambda 包含对本地的引用std::function
。即使您返回std::function
by 副本,lambda 仍将引用已死的旧版本。
为了确保返回递归 lambda 的安全,您可以将 lambda 在auto
参数中发送给自身并将其包装在另一个 lambda 中:
auto factorial = [](auto self, int i) -> int {
return (i == 1) ? 1 : i * self(self, i - 1);
};
return [factorial](int i) { return factorial(factorial, i); };
推荐阅读
- angular - 角
- javascript - 使用 JavaScript 在外部单击时如何关闭本机 HTML 对话框?
- rx-java - 让一个 observable 等待第二个,而让第二个从第一个 observable 获取最后一个发出的值
- javascript - 使用属性从数组中查找和更改对象的更好方法
- weblogic - WLST 查询(同时列出已部署的应用程序和主机)
- python - AttributeError:模块“_Box2D”没有属性“RAND_LIMIT_swigconstant”
- excel - 如何使用 excel javascript API 从受写保护的工作表中仅解锁特定单元格
- c# - 在控制器动作之间传递数据
- chart.js - 不同颜色的 Y 轴
- angular - angular 4 如何只为摸索而切片?