Явно установленный по умолчанию деструктор отключает конструктор перемещения по умолчанию в классе - PullRequest
1 голос
/ 10 июля 2019

Я столкнулся с проблемой, что конструктор перемещения суперкласса не вызывался должным образом, когда его подкласс имеет явно дефолтный деструктор. Конструктор перемещения действительно вызывается, когда деструктор неявно используется по умолчанию (вообще не указан в определении надкласса).

Мне известны ограничения , которые компиляторы должны применять к конструкторам перемещения по умолчанию. Тем не менее, я был абсолютно уверен, что компилятор не должен различать деструкторы с явным / неявным значением по умолчанию (или конструкторы, а также) при применении этих правил. Другими словами, явно дефолтный деструктор не должен рассматриваться как пользовательский (в отличие от пустой пользовательский деструктор).

Протестировано только с MSVC 2019.

Я или MSVC прямо здесь?


#include <iostream>

class A {
public:
    A() = default;
    A(const A&) { std::cout << "Auch, they'r making copy of me(?!)" << std::endl; }
    A(A&&) { std::cout << "I am moving :)" << std::endl; }

    ~A() = default;
};

class B : public A {
public:

};

class C : public A {
public:

    C() = default;

};

class D : public A {
public:

    ~D() = default;

};

class E : public A {
public:

    E() = default;
    E(const E&) = default;
    E(E&&) = default;
    ~E() = default;

};

int main()
{

    std::cout << "\n---- A ----\n" << std::endl;

    A a;
    A a2(std::move(a));

    std::cout << "\n---- B ----\n" << std::endl;

    B b;
    B b2(std::move(b));

    std::cout << "\n---- C ----\n" << std::endl;

    C c;
    C c2(std::move(c));

    std::cout << "\n---- D ----\n" << std::endl;

    D d;
    D d2(std::move(d));

    std::cout << "\n---- E ----\n" << std::endl;

    E e;
    E e2(std::move(e));

}


ОЖИДАЕТСЯ: во всех случаях отображается «Я двигаюсь :)»

АКТУАЛЬНО: Отображается «О, они делают копию меня (?!)» в случае D

1 Ответ

1 голос
/ 10 июля 2019

Когда вы объявляете деструктор по умолчанию в D, вы отключаете сгенерированный компилятором конструктор перемещения и оператор присваивания перемещения в D (!), , а не версии базового класса. Вот почему вы получаете ожидаемый результат с E, где вы переопределяете операцию по умолчанию компилятором, явно = default используя специальные функции-члены. Генерируемый компилятором конструктор перемещения делает правильные вещи для подвижных типов базовых классов, поэтому следуйте правилу из пяти и = default специальных функций-членов для D.

Посмотрите на таблицу в этом ответе . Это очень полезный справочник, который нужно держать под подушкой.

...