How does a lambda move?
I don't understand how the lambda moves. Consider the following code:
#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
}
As you can see, I am declaring a Foo
non-copyable class (but relocatable), which I pass to init capture lambda
, so lambda
it only ends up with a transition. The closure of the lambda declares a std::string
(which is movable). Then I move lambda
to moved_lambda
, so I expect to be moved std::string
. However, when I call lambda()
in main()
, it still displays the old line as if it didn't move at all.
Then I "mimicked" the lambda with functors, and when I move functor
to the moved_functor
original string
in it functor
also moves, so when I try to show it in main()
I get an empty string. I am puzzled by this behavior, why this inconsistency? I would suggest that the moved lambda (which is internally only a functional object) would move its components rather than copy them. My only explanation is that the local variables lambda
are equal internally const
, so instead of moving them, we copy them, but I'm not sure. Is this the case?
source to share
Yours Functor
doesn't match your lambda. Your lambda actually looks like this:
struct Functor // "simulate" a lambda
{
void operator()() const
{
std::string x{"functor"};
std::cout << x << std::endl;
}
};
Hopefully this helps you understand why your moved lambda still prints "lambda"
: Functor
had a x
moved but the lambda didn't.
source to share
Your examples are not identical. Correctly modeling the lambda would be as follows:
struct Functor // "simulate" a lambda
{
void operator()() const
{
std::string x{"functor"};
std::cout << x << std::endl;
}
};
Note what is x
now inside a function. The two examples now behave the same: they both print their local variables, even if they are moved.
The explanation is simple: internal variables are not copied or moved because they do not exist while the functor / lambda is copied or moved. They are created and destroyed when they are called operator()
.
source to share