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

Viewed 992

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?

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

Related