为什么这个递归 lambda 函数不安全?

2024-02-29

这个问题来自lambda 函数可以递归吗? https://stackoverflow.com/questions/14531993/can-lambda-functions-be-recursive . The 接受的答案 https://stackoverflow.com/a/14532044/8776746表示下面所示的递归 lambda 函数有效。

std::function<int (int)> factorial = [&] (int i) 
{ 
    return (i == 1) ? 1 : i * factorial(i - 1); 
};

然而,有指出一条评论 https://stackoverflow.com/questions/14531993/can-lambda-functions-be-recursive#comment20265730_14532044 that

这样的函数无法安全返回

,原因在这条评论 https://stackoverflow.com/questions/14531993/can-lambda-functions-be-recursive#comment61913320_14532044:

返回它会破坏局部变量,并且该函数具有对该局部变量的引用.

我不明白原因。据我所知,捕获变量相当于将它们保留为数据成员(根据捕获列表按值或按引用)。那么在这种情况下什么是“局部变量”呢?此外,即使使用下面的代码也可以正确编译和工作-Wall -Wextra -std=c++11选项开启g++ 7.4.0.

#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通过复制,lambda 仍将引用已失效的旧 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); };
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么这个递归 lambda 函数不安全? 的相关文章

随机推荐