Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::move doesn't work when the derived class' destructor is specified

Tags:

c++

I was trying to move an instance to another one, as follows:

#include <iostream>

class student {
public:
    student() = default;
    student(const student& student) {
        std::cout << "copy student" << std::endl;
    }
    student(student&& student) {
        std::cout << "move student" << std::endl;
    }
    virtual ~student() = default;
};

class undergraduate: public student {
public:
    undergraduate(): student() {}
    ~undergraduate() override = default; // removing this line will make std::move work
};

int main() {
    undergraduate student;
    undergraduate student1 = std::move(student);
}

Here is the output:

copy student

As you can see, std::move didn't work, student was copied instead of moved, however, if I remove undergraduate's destructor, i.e. the following line:

~undergraduate() override = default; // removing this line will make std::move work

The output will become move student, which means std::move works. Why? Why didn't std::move work when the derived class' destructor is specified?

like image 262
Searene Avatar asked Dec 27 '18 14:12

Searene


People also ask

Is destructor called after std :: move?

uninitialized_move() initializes new T objects into the new memory area by moving them from the old memory area. Then it calls the destructor on the original T object, the moved-from object.

What does std :: move () do?

std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.

Does STD move move constructor?

std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.


1 Answers

Specifying a class's destructor inhibits automatic generation of the move constructor and move assignment. You can restore them by using = default:

class undergraduate: public student {
public:
    undergraduate(): student() {}
    ~undergraduate() override = default;

    undergraduate(const undergraduate&) = default;
    undergraduate& operator=(const undergraduate&) = default;

    undergraduate(undergraduate&&) = default;
    undergraduate& operator=(undergraduate&&) = default;
};

Howard Hinnant created an excellent table for his Everything You Ever Wanted To Know About Move Semantics (and then some)" presentation:

enter image description here

like image 53
Vittorio Romeo Avatar answered Oct 08 '22 19:10

Vittorio Romeo