【问题标题】:why the move constructor/move assignment are not implicitly declared and defined as deleted if we only define copy constructor/oper=?如果我们只定义复制构造函数/oper=,为什么移动构造函数/移动赋值没有被隐式声明和定义为删除?
【发布时间】:2015-04-17 05:06:32
【问题描述】:

按照 C++ 标准 12.8.7:

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

和 12.8.18

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

我想知道如果我们只定义了复制构造函数或复制赋值运算符?

【问题讨论】:

  • 如果声明复制构造函数或复制赋值运算符,则没有“隐式声明的移动构造函数/移动赋值”。
  • @T.C.谢谢,我已经修改了问题。
  • 从 Angew 的示例代码来看,我猜主要原因之一是为了向后兼容遗留代码。

标签: c++ c++11


【解决方案1】:

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

(显然)不存在的函数不参与重载决议。定义为已删除的函数是否正常参与重载决议;如果选择了,编译会出错。

此代码compiles:

struct Normal
{
    Normal() {}

    Normal(const Normal &) {}
};


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

这段代码results in an error:

struct Deleted
{
    Deleted() {}

    Deleted(const Deleted &) {}

    Deleted(Deleted&&) = delete;
};


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

【讨论】:

  • 还有一种奇怪的情况,即默认定义为删除的移动 ctors/赋值运算符,它们被重载决议忽略。
  • @T.C.我不认为这些被“忽略”。我的印象是,措辞是“如果它被定义为删除,那么它根本就没有声明。”
  • 见[class.copy]/p11和p23的最后几句。它们被忽略了。
  • @T.C.抱歉,我似乎在 C++11 中找不到它(在您发布的点中)哪个标准版本?
  • 我指的是 N4140。让我检查一下 N3337。 (编辑 - 啊,我明白了,它有一个“不会被定义为删除”。)
【解决方案2】:

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

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

您仍然可以自己删除移动操作,如果出于某种原因您想要仅可从 左值 复制的相当奇怪的质量。

【讨论】:

    猜你喜欢
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多