rvalues与复制运算符

Pet*_*lon 15 c++ c++11

考虑这个简单的类

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:如果您不希望您的类具有移动构造函数,则只需不要定义它.如果已声明以下内容之一,编译器将不会生成移动构造函数:复制构造函数,复制赋值运算符,移动赋值运算符,析构函数.


Tar*_*ama 8

编译器正在按照你的要求进行操作.您已删除移动赋值运算符,表示您不希望允许从rvalues分配.移动分配操作符将在重载解析期间找到,并且由于它被删除,因此会发出诊断.

如果只是声明复制赋值运算符,则不会隐式声明移动赋值运算符,因此不会通过重载解析找到它,而是将调用复制赋值运算符.