I don't understand how a lambda is moved. 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 declare a Foo
non-copyable class (but movable) that I pass to the init capture of lambda
, so lambda
ends up being move-only. The lambda closure declares a std::string
(which is movable). Next I move the lambda
into moved_lambda
, so I expect the std::string
to be moved as well. However, when I invoke lambda()
in main()
, it still displays the old string, as if it wasn't moved at all.
I then "simulated" the lambdas with functors, and when moving functor
into moved_functor
, the initial string
in functor
is moved as well, so when I try displaying it in main()
I get a null string. I am puzzled by this behaviour, why this inconsistency? I would have expected that a moved lambda (which internally is just a function object) would move its components and not copy them. My only explanation is that the local variables inside the lambda
are const
, so instead of moving them we copy them, but I'm not sure. Is this the case?
Aucun commentaire:
Enregistrer un commentaire