当我编写"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");
}
答案 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构造函数是错误的。