c++ 删除基类中的移动构造函数不会停止从函数返回派生类对象

qhhrdooz  于 2023-02-17  发布在  其他
关注(0)|答案(2)|浏览(83)

给定基类A和派生类B,A删除了移动构造函数:

class A {
public: 
  A()  {}
  A(const A&) = default;
  A(A&&) = delete; 
};

class B : public A
{ 
};

在这种情况下,由于删除了移动构造函数,以下函数不会编译:

A f() {
  A a;
  return a;
}

但是B的类似函数不报告任何错误:

B g() {
  B b;
  return b;
}

这是否意味着B中的移动构造函数没有被删除?我想知道标准中的规则是什么?

1cklez4t

1cklez4t1#

B中的移动构造函数被删除,但不参与重载解析。根据cppreference:
如果以下任一条件为真,则类T的隐式声明或默认移动构造函数被定义为 deleted

  • T具有不能移动的非静态数据成员(具有已删除、不可访问或不明确的移动构造函数);
  • T具有无法移动的直接或虚拟基类(具有已删除、不可访问或不明确的移动构造函数);
  • T具有直接或虚基类或具有已删除或不可访问析构函数的非静态数据成员;
  • T是一个类联合的类,并且有一个带有非平凡移动构造函数的变体成员。

重载解析会忽略删除的默认移动构造函数(否则会阻止从右值进行复制初始化)。
第二点适用于:B具有直接基类A,其具有删除的移动构造函数,因此B的隐式声明的移动构造函数被定义为删除。
但是,当return语句计算使用B的哪个构造函数时,不考虑删除的移动构造函数,而考虑有效的复制构造函数。

hmae6n7t

hmae6n7t2#

B的移动构造函数被删除,as already answered by @Nathan Pierson
可以从g返回局部b的原因是,正如那里所解释的,B的 * 隐式删除的移动构造函数 * 不参与重载解析,因此编译器选择B的默认复制构造函数。
为了证明上述内容,请查看the following code,在B中添加一个仅可移动的成员:

class B : public A { 
  std::unique_ptr<int> ptr;
public: 
  B() {}
  // needs this to compile:
  //   B(B&& b): A(b), ptr(std::move(b.ptr)) {}  
};

B g() {
  B b;
  // now this would fail
  // B doesn't have a default move ctor
  // (it is implicitly deleted because of A)
  // and the default copy ctor is not valid
  return b; 
}

相关问题