【问题标题】:Explicitly defaulted destructor disables default move constructor in a class显式默认析构函数禁用类中的默认移动构造函数
【发布时间】:2019-07-10 10:10:33
【问题描述】:

我遇到了一个问题,即超类的移动构造函数在其子类具有显式默认析构函数时没有被正确调用。当析构函数被隐式默认(在超类定义中根本没有提供)时,移动构造函数会被调用。

我知道编译器应将constraints 应用于默认移动构造函数。然而,我一直确信编译器在应用这些规则时不应区分显式/隐式默认析构函数(或构造函数)。换句话说,显式默认的析构函数不应被视为用户定义的析构函数(与 empty 用户定义的析构函数相反)。

仅使用 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));

}


预期:在所有情况下都显示“我正在移动:)”

ACTUAL :显示“哎呀,他们在复制我(?!)”以防 D

【问题讨论】:

    标签: c++ c++11 default destructor move-semantics


    【解决方案1】:

    当您在D 中声明默认析构函数时,您会在D (!) 中禁用编译器生成的移动构造函数和移动赋值运算符,不是基类版本。这就是为什么您使用E 获得预期输出的原因,您可以通过显式= defaulting 特殊成员函数来覆盖编译器的默认操作。编译器生成的移动构造函数对可移动基类类型执行正确的操作,因此请遵循 rule of five 和 = default 的特殊成员函数 D。

    查看this answer 中的表格。放在枕头下是非常有用的参考。

    【讨论】:

    • 非常感谢。在this presentation 中的link to SO 中滑动14,您为我提供了我一直在寻找的答案。 ps 是的,我知道它属于 B 的 ctors。我编辑了这个问题的标题以供将来参考(原文具有误导性)
    猜你喜欢
    • 2022-01-09
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 2013-03-16
    • 2016-02-05
    • 2018-02-02
    相关资源
    最近更新 更多