lambda是如何移动的

How is a lambda moved?

本文关键字:移动 何移动 lambda      更新时间:2023-10-16
我不明白lambda是如何移动的。考虑以下代码:
#include <iostream>
#include <utility>
#include <string>
struct Foo // non-copyable type
{
Foo() = default;
Foo(const Foo&) = delete; // cannot copy
Foo(Foo&&) = default; // can move
};
auto lambda = [p = Foo()](){
std::string x{"lambda"}; 
std::cout << x << std::endl;
};
// auto copied_lambda = lambda; // cannot copy due to Foo non-copyable init capture
auto moved_lambda = std::move(lambda); // we moved it
struct Functor // "simulate" a lambda
{
std::string x{"functor"};
void operator()() const
{
std::cout << x << std::endl;
}
};
Functor functor; // initial functor object
auto moved_functor = std::move(functor); // moved it
int main()
{
lambda(); // why does it display "lambda" since it was moved?
moved_lambda(); // displays "lambda", was moved in, everything OK
functor(); // doesn't display "functor", was moved
moved_functor(); // displays "functor", was moved in, everything OK
}

正如您所看到的,我声明了一个Foo不可复制(但可移动)的类,并将其传递给lambda的init捕获,因此lambda最终只被移动。lambda闭包声明了一个std::string(它是可移动的)。接下来,我将lambda移动到moved_lambda中,因此我希望std::string也会移动。然而,当我在main()中调用lambda()时,它仍然显示旧字符串,就好像它根本没有移动一样。

然后,我用函子"模拟"了Lambda,当将functor移动到moved_functor时,functor中的初始string也会移动,所以当我尝试在main()中显示它时,我得到了一个空字符串。我对这种行为感到困惑,为什么会出现这种不一致?我本以为移动的lambda(内部只是一个函数对象)会移动其组件,而不是复制它们。我唯一的解释是lambda中的局部变量是const,所以我们没有移动它们,而是复制它们,但我不确定。是这样吗?

您的示例不完全相同。λ的正确模拟是:

struct Functor // "simulate" a lambda
{
void operator()() const
{
std::string x{"functor"};
std::cout << x << std::endl;
}
};

请注意,x现在位于函数内部。这两个例子现在的行为是一样的:它们都打印它们的局部变量,即使它们被移动了。

解释很简单:内部变量不会被复制或移动,因为在复制或移动函子/lambda时它们不存在。它们被创建&当调用它们的operator()时被销毁。

您的Functor与lambda不一致。您的lambda实际上看起来像:

struct Functor // "simulate" a lambda
{
void operator()() const
{
std::string x{"functor"};
std::cout << x << std::endl;
}
};

希望这有助于弄清楚为什么你的"从lambda移动"仍然打印"lambda"Functorx被从中移动,但lambda没有。