如果我们只定义复制构造函数/oper=,为什么移动构造函数/move赋值没有隐式声明和定义为删除

why the move constructor/move assignment are not implicitly declared and defined as deleted if we only define copy constructor/oper=?

本文关键字:定义 构造函数 声明 赋值 删除 为什么 复制 我们 oper 移动 如果      更新时间:2023-10-16

根据C++标准12.8.7:

如果类定义声明了move构造函数或move赋值运算符,隐式声明的复制构造函数为定义为已删除;

和12.8.18

如果类定义声明了移动构造函数或移动赋值运算符,定义了隐式声明的复制赋值运算符已删除;

我想知道,如果我们只定义了复制构造函数或复制赋值运算符,为什么移动构造函数/移动赋值没有隐式声明并定义为已删除(在这种情况下,c++11标准不会生成隐式声明的移动构造函数/移动赋值)?

如果是这种情况,那么使用右值作为构造或组装的源将导致编译错误,而不是返回到副本。

一个不存在的函数(显然)不参与过载解决。被定义为已删除的函数正常参与过载解决;如果选择了它,编译将导致一个错误。

此代码编译:

struct Normal
{
    Normal() {}
    Normal(const Normal &) {}
};

int main()
{
    Normal n(Normal{});
}

当此代码导致错误时:

struct Deleted
{
    Deleted() {}
    Deleted(const Deleted &) {}
    Deleted(Deleted&&) = delete;
};

int main()
{
    Deleted d(Deleted{});
}

如果在这种情况下删除了移动构造函数,那么尝试从右值复制初始化将是一个错误-删除的移动构造函数将比复制构造函数更匹配。

通常,如果您没有定义移动语义,您会希望复制初始化为复制,而不是被禁止。为了给出这种行为,move构造函数根本没有声明,因此无论是从左值还是从rvalue复制,复制初始化都使用复制构造函数。(只要复制构造函数通过const引用获取其参数即可。)

如果出于某种原因,您希望只能从左值复制这种相当奇怪的质量,那么您仍然可以自己删除移动操作。