34
4

1 回答 1

43

删除的移动成员是邪恶的。它们并没有被取缔,因为有一天,有人会为它们找到一个聪明的用途。但是我还没有看到好的用途。

删除特殊成员与没有特殊成员不同。没有什么比使用移动构造函数和移动赋值运算符更明显了。

当存在时,无论是删除的、默认的还是用户定义的,移动构造函数和移动赋值运算符都参与重载决议。这意味着他们与特殊副本成员“竞争”。复制成员通常会偏爱 const 左值,而移动成员会吸引右值。

当从函数返回局部类型时(当局部类型与返回类型是相同的 un-cv-qualified 类型时),return 语句首先将返回表达式视为右值,并且只有在找不到合适的构造函数,然后将其视为左值。即匹配正确的构造函数以从函数返回本地对象是一个两阶段操作。

当你根本没有移动构造函数(甚至没有删除),但你有一个普通的复制构造函数(接受一个 const &)时,return 语句中的右值将匹配复制构造函数。

如果确实有移动构造函数,即使它被标记为已删除,return 语句中的右值也会发现移动构造函数比复制构造函数更匹配。

概括

除非您真的知道自己在做什么,否则永远不要删除移动成员。如果您不希望您的类型是可移动的,只需不要定义移动成员并确保您确实声明了复制成员,即使复制成员是=default'd。

更新

我想很难从标准中引用 delete 不能做什么?– DyP

8.4.3 删除的定义 [dcl.fct.def.delete]

2 隐式或显式引用已删除函数的程序,而不是声明它,是格式错误的。[注意:这包括隐式或显式调用函数并形成指向函数的指针或指向成员的指针。它甚至适用于未潜在评估的表达式中的引用。如果函数被重载,则仅当函数被重载决议选择时才会被引用。——尾注]

更新 2

12.8 复制和移动类对象[class.copy]

9 如果类 X 的定义没有显式声明移动构造函数,当且仅当

  • X 没有用户声明的复制构造函数,
  • X 没有用户声明的复制赋值运算符,
  • X 没有用户声明的移动赋值运算符,并且
  • X 没有用户声明的析构函数。

[注意:当移动构造函数没有被隐式声明或显式提供时,否则会调用移动构造函数的表达式可能会调用复制构造函数。——尾注]

于 2013-05-23T00:55:47.583 回答