CErjk
CErjk

Reputation: 31

Why defining move constructor deletes move assignment operator

When i write "f5() = X(33);"(when move constructor in comment line) the compiler does not throw errors. But when I add a Move Constructor compiler says:

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

is move constructor delete assignment operator ??

#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");
}

Upvotes: 2

Views: 1233

Answers (2)

Eugene
Eugene

Reputation: 7188

The error message ('X &X::operator =(const X &)': function was implicitly deleted because 'X' has a user-defined move constructor) clearly answers "yes" to your question. But you apparently want to know the motivation for this rule in C++.

The rule was introduced in C++11 (together with move semantics) to enforce the "Rule of 3/5", which says that all of the following must be used together or not at all:

  • copy constructor
  • copy assignment operator
  • move constructor
  • move assignment operator
  • destructor

(in some situations, it is ok to omit move or copy aiir of constructor/assignment).

Similarly, it would make sense to delete the copy assignment operator when a copy constructor is defined, but it could not be done in 2011 to preserve backward compatibility.

Your code is a good illustration of why the Rule of 3/5 is needed. As is, your class leaks memory. If you add a destructor with delete p, but don't define a move assignment operator, then with your example you get a double deletion (undefined behavior, likely crash).

Finally, note that your move constructor is wrong.

Upvotes: 4

Jeffrey
Jeffrey

Reputation: 11400

f5() = X(33);

would be calling the assignment operator, because an X object already exists there. It's an assignment, not a construction. Before you had a move constructor, it was calling an auto-generated assignment operator.

Now, the compiler is unwilling (well, forbidden) to generate a default assignment operator because you implement a move constructor. The logic goes, you probably know better about your type, so it will let you implement

X &X::operator =(const X &)

Upvotes: 4

Related Questions