为什么定义移动构造函数会删除移动分配运算符

时间:2019-10-02 17:18:52

标签: c++

当我编写"f5() = X(33);"时(在注释行中移动构造函数时),编译器不会引发错误。 但是当我添加一个Move Constructor编译器时说:

" 'X &X::operator =(const X &)': attempting to reference a deleted function "

是移动构造函数删除赋值运算符??

#include <iostream>

class X {
    int* p;
public:
    X(int ii = 0) { p = new int(ii); };
    X(const X& obj) { this->p = new int(*(obj.p)); };
//  X(X&& obj) { this->p = new int(*(obj.p)); delete obj.p; obj.p=nullptr;
};



X f5() {
    return X(5);
}

int main() {

    f5() = X(33);
    system("pause");
}

2 个答案:

答案 0 :(得分:2)

    [Fact]
    public void RandomOperation()
    {
        Helper.RunWithMultipleSimulators((s) =>
        {
            Circuits.RandomOperationTest.Run(s).Wait(); // Throws if it doesn't succeed
        });
    }

将调用赋值运算符,因为那里已经存在X对象。这是一项任务,而不是建设。在您拥有move构造函数之前,它正在调用一个自动生成的赋值运算符。

现在,编译器不愿意(很好,禁止)生成默认的赋值运算符,因为您实现了move构造函数。顺理成章,您可能对类型有所了解,因此可以实现

f5() = X(33);

答案 1 :(得分:2)

错误消息('X &X::operator =(const X &)': function was implicitly deleted because 'X' has a user-defined move constructor)清楚地回答了您的问题。但是您显然想知道C ++中此规则的动机。

该规则在C ++ 11中(与移动语义一起)引入以实施“ 3/5规则”,该规则规定以下所有条件必须一起使用或完全不使用:

  • 复制构造函数
  • 复制分配运算符
  • 移动构造函数
  • 移动分配运算符
  • 析构函数

(在某些情况下,可以省略移动或复制构造函数/赋值的路径)。

类似地,定义副本构造函数时删除副本分配运算符很有意义,但在2011年无法做到这一点,以保持向后兼容性。

您的代码很好地说明了为什么需要3/5规则的原因。照原样,您的课程会泄漏内存。如果您添加带有delete p的析构函数,但未定义移动分配运算符,则在您的示例中您将得到两次删除(未定义的行为,可能会崩溃)。

最后,请注意,您的move构造函数是错误的。