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?

+3


source to share


2 answers


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.

+4


source


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()

.

+5


source







All Articles