vendredi 24 avril 2015

How is a lambda moved?

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