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

Yan*_*hao 19 c++ inheritance constructor move-semantics

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

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

class B : public A
{ 
};
Run Code Online (Sandbox Code Playgroud)

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

A f() {
  A a;
  return a;
}
Run Code Online (Sandbox Code Playgroud)

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

B g() {
  B b;
  return b;
}
Run Code Online (Sandbox Code Playgroud)

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

Nat*_*son 22

中的移动构造函数B被删除,但不参与重载决策。根据cppreference

如果满足以下任一条件,则类 T 的隐式声明或默认移动构造函数被定义为已删除:

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

重载决策会忽略已删除的默认移动构造函数(否则会阻止从右值进行复制初始化)。

第二个要点适用:B有一个直接基类 ,A带有删除的移动构造函数。SoB的隐式声明的移动构造函数被定义为已删除。

但是,当 return 语句评估B要使用哪个构造函数时,不会考虑已删除的移动构造函数,而是考虑有效的复制构造函数。


Ami*_*rsh 13

的移动构造函数B已被删除,正如 @Nathan Pierson 已经回答的那样

b您可以返回本地from的原因g是,正如那里所解释的,隐式删除的移动构造函数B参与重载决策,因此编译器选择 的默认复制构造函数B

为了证明上述内容,请看下面的代码,添加一个仅可移动的成员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; 
}
Run Code Online (Sandbox Code Playgroud)