自动生成带有不可移动成员的移动构造函数

Automatically generated move constructor with not movable members

本文关键字:移动 构造函数 成员 可移动 自动生成      更新时间:2023-10-16

我遇到了一种非常有趣的情况,因为我正在编译代码,尽管我很惊讶,所以我想问你的看法。

情况是这样的。我有一个带有删除的移动和复制构造函数的类,它具有用户定义的赋值操作符:

struct A {
    A() { }
    A(const A&) = delete;
    A(A&& ) = delete;
    A& operator=(const A& ) { return *this; }
    A& operator=(A&& ) { return *this; }
};

我有另一个类,A是唯一的成员。在本课程中,我定义了复制构造函数,但将move构造函数保留为默认值,并通过调用swap函数定义了赋值操作符:

class B{
public:
    A a;
    B()
    : a{}
    { }
    B(const B&)
    : a{}
    { }
    B(B&& other) = default;
};
int main() {
    B b1;
    B b2(std::move(b1)); // compiles??
}

为什么默认的移动构造函数可以工作,考虑到它不能简单地调用移动或复制构造函数A?

我原来的答案错了,所以我重新来过。


(班上

。Copy],我们有:

一个默认的副本/类X的move构造函数定义为deleted(8.4.3),如果X具有:
- - - - - -[…]
-一个潜在构造的子对象类型M(或其数组)不能被复制/移动,因为重载解析(13.3)应用于M的相应构造函数时,会导致歧义或a被删除或从默认构造函数
中无法访问的函数- - - - - -[…)

该要点适用于B(B&& other) = default;,因此move构造函数被定义为deleted。这似乎会破坏std::move()的编译,但我们也有(通过缺陷1402的解决方案):

定义为deleted的默认move构造函数被重载解析(13.3, 13.4)忽略。(注意:被删除的move构造函数会干扰右值的初始化,右值可以使用而是复制构造函数。

忽略是关键。因此,当我们这样做时:

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

即使删除了B的移动构造函数,这段代码仍然是格式良好的,因为移动构造函数根本不参与重载解析,而是调用复制构造函数。因此,B是MoveConstructible——即使你不能通过它的move构造函数来构造它。