【问题标题】:How to use move constructor with deleted default consturctor如何将移动构造函数与已删除的默认构造函数一起使用
【发布时间】:2021-01-05 00:49:52
【问题描述】:

我有一段这样的现有代码:

struct Base {
    Base() = default;
};

struct Derive: public Base
{
    Derive() = default;
    Derive(const Derive&) = delete;
    Derive(Derive&& p) { *this = std::move(p); }
    Derive& operator = (const Derive& p) = delete;
    Derive& operator = (Derive&& p) {
        return *this;
    }
};

int main() {
  Derive p;
}

它编译并工作。现在我想稍微更改类定义,以便始终使用某些整数参数构造 Base 或 Derived 类,并且永远不会在没有此类参数的情况下构造。

所以如果我尝试以下更改:

struct Base {
    Base() = delete;
    Base(int a_) : a{a_} {};
private:
  int a; //new mandatory param;
};

struct Derive: public Base
{
    Derive() = delete;
    Derive(int a_) : Base(a_) {};
    Derive(const Derive&) = delete;
    Derive(Derive&& p) { *this = std::move(p); }
    Derive& operator = (const Derive& p) = delete;
    Derive& operator = (Derive&& p) {
        return *this;
    }
};

int main() {
  Derive p{1};
}

我得到编译错误

main.cpp:15:2: error: call to deleted constructor of 'Base'
        Derive(Derive&& p) { *this = std::move(p); }
        ^
main.cpp:4:2: note: 'Base' has been explicitly marked deleted here
        Base() = delete;
        ^
1 error generated.

显然这种方式行不通。那么如何修改代码以使其编译并且永远不会调用任何参数构造函数而不会出错?

【问题讨论】:

    标签: c++ class move-constructor


    【解决方案1】:

    问题

    Derive(Derive&& p) xxx { *this = std::move(p); }
    

    是在xxx 部分你有一个空的member initialization list。这意味着编译器将为基类插入一个,因为在执行构造函数主体之前,所有成员都在成员初始化列表中进行了初始化。该编译器生成的版本看起来像

    Derive(Derive&& p) : Base() { *this = std::move(p); }
    

    你不能这样做 Base() 因为它已被删除。你想要的是

    Derive(Derive&& p) : Base(std::move(p)) {}
    

    甚至更短

    Derive(Derive&& p) = default;
    

    【讨论】:

      【解决方案2】:

      您不需要显式删除基类中的默认 ctor。简单地定义一个需要参数的 ctor 会阻止编译器生成默认 ctor,因此您的基类可以是:

      struct Base {
          Base(int a_) : a{a_} {};
      private:
        int a; //new mandatory param;
      };
      

      同样,在您的派生类中,定义一个接受参数的 ctor 会阻止编译器为其生成默认 ctor。至少到目前为止,您提到的任何内容似乎都表明您需要为派生类显式定义任何特殊成员函数,因此它可以变得简单:

      struct Derive: public Base
      {
          Derive(int a_) : Base(a_) {};
      };
      

      ...现在代码编译得很好,任何尝试创建 BaseDerive 的实例而不为 ctor 指定参数的尝试都将失败(不会编译)。

      顺便说一句,由于您将它用作基类,您可能希望Base 将其dtor 设为虚拟。在这里将其定义为默认值可能比较合适。

      【讨论】:

        猜你喜欢
        • 2016-12-16
        • 1970-01-01
        • 1970-01-01
        • 2013-03-16
        • 2016-09-13
        • 1970-01-01
        • 2013-08-19
        • 2017-05-10
        • 2016-01-01
        相关资源
        最近更新 更多