Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the move constructor not called when moving in a lambda?

I am trying to compile the following code:

#include <utility>

struct C2 {
        C2() = default;
        C2(C2 const&) = delete;
        C2(C2&&) = default;
};

int main() {
        C2 p2;
        ([p2_1{ std::move(p2) }]() {
                auto p2_2 = std::move(p2_1); // <---
        })();
        return 0;
}

However, this doesn't compile and gives an error that the assignment to p2_2 is calling a deleted function, namely the copy constructor. Note that the move to p2_1 is fine. Why is this not using the move constructor?

like image 568
Baruch Avatar asked Feb 14 '17 20:02

Baruch


People also ask

Are move constructors automatically generated?

If a copy constructor, copy-assignment operator, move constructor, move-assignment operator, or destructor is explicitly declared, then: No move constructor is automatically generated. No move-assignment operator is automatically generated.

Where is the move constructor used?

A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying. For more information about move semantics, see Rvalue Reference Declarator: &&. This topic builds upon the following C++ class, MemoryBlock , which manages a memory buffer. // MemoryBlock.

What is the difference between a move constructor and a copy constructor?

Move constructor moves the resources in the heap, i.e., unlike copy constructors which copy the data of the existing object and assigning it to the new object move constructor just makes the pointer of the declared object to point to the data of temporary object and nulls out the pointer of the temporary objects.

Is move constructor faster than copy constructor?

It's faster because moving allows the source to be left in a invalid state, so you can steal it's resources. For example, if a object holds a pointer to a large block of allocated memory, a move can simply steal the pointer while a copy must allocate its own memory and copy the whole memory block.


1 Answers

The catch here is that the operator() of the anonymous class type the lambda represents is const by default. That means you can't move from p2_1 since the this of the lambda is const& in the function. What you need to do is use the mutable keyword like

int main() {
        C2 p2;
        ([p2_1{ std::move(p2) }]() mutable {
                auto p2_2 = std::move(p2_1); // <---
        })();
        return 0;
}

Which makes the function non const which in turn means you can mutate its members. This allows you to move p2_1 instead of trying to copy it.

like image 132
NathanOliver Avatar answered Oct 31 '22 22:10

NathanOliver