考虑这个简单的类
class Foo
{
public:
Foo() = default;
Foo(const Foo &) = default;
Foo & operator=(const Foo & rhs)
{
return *this;
}
Foo & operator=(Foo && rhs) = delete;
};
Foo getFoo()
{
Foo f;
return f;
}
int main()
{
Foo f;
Foo & rf = f;
rf = getFoo(); // Use of deleted move assignment.
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我编译上面的例子时,我得到了 error: use of deleted function 'Foo& Foo::operator=(Foo&&)'
从复制分配:
如果只提供了复制赋值,则所有参数类别都会选择它(只要它按值获取其参数或作为const的引用,因为rvalues可以绑定到const引用),这使得复制赋值成为移动赋值的后备,当移动时不可用.
当const lvalue引用可以绑定到rvalue并且const Foo & f = getFoo();有效时,为什么编译器不会回退到复制赋值.
编译器 - gcc 4.7.2.
ser*_*gej 10
没有后备,这个概念称为重载决策.
编译器执行重载决策并在检查方法是否被删除之前做出决定.编译器决定移动构造函数是最佳选择,然后它确定此方法已被删除,因此错误.
注1:
delete不会逐字删除该方法.如果delete使用,则该方法被定义为已删除,但仍可通过重载决策找到.
从cppreference.com文档(强调我的):
... 首先发生重载决策,如果选择了删除的功能,程序只会形成错误.
在您的示例中,移动构造函数是可用的(从重载解析的角度来看).但是,它被定义为已删除.
注意2:如果您不希望您的类具有移动构造函数,则只需不要定义它.如果已声明以下内容之一,编译器将不会生成移动构造函数:复制构造函数,复制赋值运算符,移动赋值运算符,析构函数.
编译器正在按照你的要求进行操作.您已删除移动赋值运算符,表示您不希望允许从rvalues分配.移动分配操作符将在重载解析期间找到,并且由于它被删除,因此会发出诊断.
如果只是声明复制赋值运算符,则不会隐式声明移动赋值运算符,因此不会通过重载解析找到它,而是将调用复制赋值运算符.