返回捕获 lambda 的 lambda

问题描述

尝试包装 lambda 的以下(简化)代码在某些 Clang 版本中向我发出警告,但不是全部,也不是 gcc。

template<typename Lambda>
auto wrapLambda(Lambda lambda)
{
    return [&lambda]() {
        lambda();
    };
}

auto wrappedLambda = wrapLambda([](){ return 0; });
warning: address of stack memory associated with parameter 'lambda' returned [-Wreturn-stack-address]  
    return [&lambda]() {  
             ^~~~~~

这是一个错误,还是我遗漏了什么?我在 godboltx86-64 clang (trunk) 中收到警告,clang version 11.1.0 作为更大存储库的一部分,但我无法隔离该版本的故障。

this related question 中的示例没有给出警告。


改进(我认为)版本:

template<typename Callable>
auto wrapCallable(Callable&& callable)
{
    return [callable = std::forward<Callable>(callable)]() {
        callable();
    };
}

auto wrappedCallable = wrapCallable([](){ return 0; });

这会用 godbolt 中的 x86-64 clang (trunk) 使警告静音。我认为它应该安全地适用于任何函子,我缺少什么?

解决方法

问题与此代码完全相同:

SomeType& foo(int x)
{
    SomeType bar{x};
    return bar; // undefined behavior returning reference to local object
}

您的 lambda 正在通过引用捕获本地对象,因此当您返回它时,这将导致未定义的行为,因为捕获的对象不再存在。

当你使用这个 lambda 时,很可能程序会崩溃(如果你不走运的话不会)。

所以这是您代码中的错误,clang 正在正确地抱怨。

问题更新后编辑:
更新问题后,新代码会为 lambda 创建参数的副本(或移动副本)。结果是返回的 lambda 没有携带对局部变量的引用,所以现在可以了。