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");
}
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 &)
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.
Related
So if I've got a class and declare a copy assignment operator in it, obviously I want some special behavior when copying. I would expect the language to try to help me out by implicitly deleting the copy constructor until I explicitly bring it back, so as to avoid unintended different behavior when doing type instance = type() as opposed to already_existing_instance = type().
It's recommended anyway that you explicitly declare both copy constructor and copy assignment operator when trying to declare one of them, precisely because C++ doesn't delete the other and causes you a headache.
An example of where I find this annoying is when deleting the copy assignment operator. If I want to quickly make a class non-copyable, I would expect deleting the copy assignment operator does the trick, but I have to explicitly delete the copy constructor as well.
My question is why does the compiler do this? Who thought this was a good idea? All it does is create a needless obstacle for the programmer or am I missing something?
P.S. This behavior doesn't present itself when doing the same thing with move constructors/assignment operators, why make a distinction between copy and move in this case?
Them not being deleted is deprecated.
E.g. Clang 15 with -Wextra, given
struct A
{
A() {}
A(const A &) {}
};
int main()
{
A a, b;
a = b;
}
spits
<source>:4:5: warning: definition of implicit copy assignment operator for 'A' is deprecated because it has a user-provided copy constructor [-Wdeprecated-copy-with-user-provided-copy]
A(const A &) {}
^
<source>:10:7: note: in implicit copy assignment operator for 'A' first required here
a = b;
^
Similarly,
struct A
{
A() {}
A &operator=(const A &) {return *this;}
};
int main()
{
A a, b(a);
}
gives
<source>:4:8: warning: definition of implicit copy constructor for 'A' is deprecated because it has a user-provided copy assignment operator [-Wdeprecated-copy-with-user-provided-copy]
A &operator=(const A &) {return *this;}
^
<source>:9:10: note: in implicit copy constructor for 'A' first required here
A a, b(a);
^
I don't understand the difference between assignment constructor and copy constructor in C++. It is like this:
class A {
public:
A() {
cout << "A::A()" << endl;
}
};
// The copy constructor
A a = b;
// The assignment constructor
A c;
c = a;
// Is it right?
I want to know how to allocate memory of the assignment constructor and copy constructor?
A copy constructor is used to initialize a previously uninitialized object from some other object's data.
A(const A& rhs) : data_(rhs.data_) {}
For example:
A aa;
A a = aa; //copy constructor
An assignment operator is used to replace the data of a previously initialized object with some other object's data.
A& operator=(const A& rhs) {data_ = rhs.data_; return *this;}
For example:
A aa;
A a;
a = aa; // assignment operator
You could replace copy construction by default construction plus assignment, but that would be less efficient.
(As a side note: My implementations above are exactly the ones the compiler grants you for free, so it would not make much sense to implement them manually. If you have one of these two, it's likely that you are manually managing some resource. In that case, per The Rule of Three, you'll very likely also need the other one plus a destructor.)
The difference between the copy constructor and the assignment operator causes a lot of confusion for new programmers, but it’s really not all that difficult. Summarizing:
If a new object has to be created before the copying can occur, the copy constructor is used.
If a new object does not have to be created before the copying can occur, the assignment operator is used.
Example for assignment operator:
Base obj1(5); //calls Base class constructor
Base obj2; //calls Base class default constructor
obj2 = obj1; //calls assignment operator
Example for copy constructor:
Base obj1(5);
Base obj2 = obj1; //calls copy constructor
The first is copy initialization, the second is just assignment. There's no such thing as assignment constructor.
A aa=bb;
uses the compiler-generated copy constructor.
A cc;
cc=aa;
uses the default constructor to construct cc, and then the *assignment operator** (operator =) on an already existing object.
I want know how to allocate memory of the assignment constructor and copy constructor?
IDK what you mean by allocate memory in this case, but if you want to see what happens, you can:
class A
{
public :
A(){ cout<<"default constructor"<<endl;};
A(const A& other){ cout<<"copy constructor"<<endl;};
A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};
I also recommend you take a look at:
Why is copy constructor called instead of conversion constructor?
What is The Rule of Three?
In a simple words,
Copy constructor is called when a new object is created from an existing object, as a copy of the existing object.
And assignment operator is called when an already initialized object is assigned a new value from another existing object.
Example-
t2 = t1; // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1; // calls copy constructor, same as "Test t3(t1);"
What #Luchian Grigore Said is implemented like this
class A
{
public :
int a;
A(){ cout<<"default constructor"<<endl;};
A(const A& other){ cout<<"copy constructor"<<endl;};
A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};
void main()
{
A sampleObj; //Calls default constructor
sampleObj.a = 10;
A copyConsObj = sampleObj; //Initializing calls copy constructor
A assignOpObj; //Calls default constrcutor
assignOpObj = sampleObj; //Object Created before so it calls assignment operator
}
OUTPUT
default constructor
copy constructor
default constructor
assignment operator
the difference between a copy constructor and an assignment constructor is:
In case of a copy constructor it creates a new object.(<classname> <o1>=<o2>)
In case of an assignment constructor it will not create any object means it apply on already created objects(<o1>=<o2>).
And the basic functionalities in both are same, they will copy the data from o2 to o1 member-by-member.
I want to add one more point on this topic.
"The operator function of assignment operator should be written only as a member function of the class." We can't make it as friend function unlike other binary or unary operator.
Something to add about copy constructor:
When passing an object by value, it will use copy constructor
When an object is returned from a function by value, it will use copy constructor
When initializing an object using the values of another object(as the example you give).
http://en.cppreference.com/w/cpp/language/rule_of_three
I have begun with c++11 a couple of months ago
and have watched the rule of five.
So.. I started putting copy constructor/copy assignment operator/move constructor/move assignment operator with default keyword on every class having virtual destructor.
because the rule told me that if you declare explicit destructor then your class doesn't have its implicit move constructor and move assignment operator anymore.
So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.
But It works well! What happend??
class Interface {
public:
virtual ~Interface() = default; // implicit destructor
};
class ImplA : public Interface {
public:
virtual ~ImplA() = default; // implicit destructor
};
ImplA first;
ImplA second(first); // copy constructor, OK. understood it.
ImplA third(std::move(first)); // move constructor, it's OK. Why?
second = first; // copy assignment, OK. understood it.
second = std::move(first); // move assignment, it's also OK. Why?
So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.
Because the operations required could be performed via copy constructor and copy assignment operator. Interface still has copy constructor and copy assignment operator which are implcitly declared. And rvalues are always possible to be bound to const Interface&.
More precisely, even without move constructor and move assignment operator provided, Interface is still MoveConstructible,
A class does not have to implement a move constructor to satisfy this
type requirement: a copy constructor that takes a const T& argument
can bind rvalue expressions.
and MoveAssignable.
The type does not have to implement move assignment operator in order
to satisfy this type requirement: a copy assignment operator that
takes its parameter by value or as a const Type&, will bind to rvalue
argument.
BTW: If you make the move constructor and move assignment operator delete explicitly then both copy and move operation would fail. Using with an rvalue expression the explicitly deleted overload will be selected and then fails. Using with an lvalue expression would fail too because copy constructor and copy assignment operator are implicitly declared as deleted because of the declaration of move constructor or move assignment operator.
For some time this has been confusing me. And I've not been able to find a satisfactory answer thus far. The question is simple. When does a move assignment operator get called, and when does a move constructor operator get called?
The code examples on cppreference.com yield the following interesting results:
The move assignment operator:
a2 = std::move(a1); // move-assignment from xvalue
The move constructor:
A a2 = std::move(a1); // move-construct from xvalue
So has it do to with which is implemented? And if so which is executed if both are implemented? And why is there the possibility of creating a move assignment operator overload at all, if it's identical anyway.
A move constructor is executed only when you construct an object. A move assignment operator is executed on a previously constructed object. It is exactly the same scenario as in the copy case.
Foo foo = std::move(bar); // construction, invokes move constructor
foo = std::move(other); // assignment, invokes move assignment operator
If you don't declare them explicitly, the compiler generates them for you (with some exceptions, the list of which is too long to be posted here).
See this for a complete answer to when the move member functions are implicitly generated.
When does a move assignment operator get called
When you assign an rvalue to an object, as you do in your first example.
and when does a move constructor operator get called?
When you initialise an object using an rvalue, as you do in your second example. Although it isn't an operator.
So has it do to with which is implemented?
No, that determines whether it can be used, not when it might be used. For example, if there's no move constructor, then construction will use the copy constructor if that exists, and fail (with an error) otherwise.
And if so which is executed if both are implemented?
Assignment operator for assignment, constructor for initialisation.
And why is there the possibility of creating a move assignment operator overload at all, if it's identical anyway.
It isn't identical. It's invoked on an object that already exists; the constructor is invoked to initialise an object which previously didn't exist. They often have to do different things. For example, assignment might have to delete something, which won't exist during initialisation.
This is the same as normal copy assignment and copy construction.
A a2 = std::move(a1);
A a2 = a1;
Those call the move/copy constructor, because a2 doesn't yet exist and needs to be constructed. Assigning doesn't make sense. This form is called copy-initialization.
a2 = std::move(a1);
a2 = a1;
Those call the move/copy assignment operator, because a2 already exists, so it doesn't make sense to construct it.
Move constructor is called during:
initialization: T a = std::move(b); or T a(std::move(b));, where b is of type T;
function argument passing: f(std::move(a));, where a is of type T and f is void f(T t);
Move assignment operation is called during:
function return: return a; inside a function such as T f(), where a is of type T which has a move constructor.
assignment
The following example code illustrates this :
#include <iostream>
#include <utility>
#include <vector>
#include <string>
using namespace std;
class A {
public :
A() { cout << "constructor called" << endl;}
~A() { cout << "destructor called" << endl;}
A(A&&) {cout << "move constructor called"<< endl; return;}
A& operator=(A&&) {cout << "move assignment operator called"<< endl; return *this;}
};
A fun() {
A a; // 5. constructor called
return a; // 6. move assignment operator called
// 7. destructor called on this local a
}
void foo(A){
return;
}
int main()
{
A a; // 1. constructor called
A b; // 2. constructor called
A c{std::move(b)}; // 3. move constructor called
c = std::move(a); // 4. move assignment operator called
a = fun();
foo(std::move(c)); // 8. move constructor called
}
Output :
constructor called
constructor called
move constructor called
move assignment operator called
constructor called
move assignment operator called
destructor called
move constructor called
destructor called
destructor called
destructor called
destructor called
I have a simple class which contains an std::vector, and I would like to benefit from move semantics (not RVO) when returning the class by value.
I implemented the move constructor, copy constructor and copy assignment operators in the following way:
class A
{
public:
// MOVE-constructor.
A(A&& other) :
data(std::move(other.data))
{
}
// COPY-constructor.
A(const A& other) :
data(other.data)
{
}
// COPY-ASSIGNMENT operator.
A& operator= (const A& other);
{
if(this != &other)
{
data = other.data;
}
return *this;
}
private:
std::vector<int> data;
};
Are the above implementations correct?
And an other question: do I even have to implement any of these members, or are they auto-generated by the compiler? I know that the copy-constructor and the copy-assignment operator are generated by default, but can the compiler auto-generate the move constructor as well? (I compile this code both with MSVC and GCC.)
Thanks in advance for any suggestions. (I know that there already are some similar questions, but not for this exact scenario.)
They're all unnecessary for this class[*], since it would have implicit ones if you didn't declare any of them.
Your constructors are fine. So the following code ostensibly calls the move constructor:
A f() { return A(); }
A a = f(); // move construct (not copy construct) from the return value of f
In fact move-elision might kick in, in which case only the no-args constructor is actually called. I assume you plan to provide some constructors other than copy and move ;-)
Your copy assignment is fine, it differs from the implicit one only in that it has the self-assignment check, which the implicit one would not. I don't think we should have the argument whether a self-assignment check is worth it or not, it's not incorrect.
You haven't defined a move-assignment operator. Given that you defined the others, you should have done, but if you get rid of the rest it's implicit[*]. The move assignment operator (whether user-defined or implicit) is what ensures that the following code will move instead of copying:
A a;
a = f();
[*] On a completed C++11 implementation, of which so far none exist. You can check on a per-compiler basis whether this feature is implemented yet, and probably you'll end up with some horrible #define shenanigans until MSVC does.
For this exact scenario, You don't need to declare any move/copy/assignment functions. Compiler will generate correct defaults.