Home > Back-end >  Copy constructor and default assignment operator
Copy constructor and default assignment operator

Time:03-31

I have made the following Car class:

class Car
{
private:
    int  id;
    int* data;
public:
    Car(int id, int data) : id(id) , data(new int(data)){}
    //Car(const Car& rhs) : id(rhs.id) , data(new int(*rhs.data)){}
    void print(){std::cout << id << " - " << *data << " - " << data << std::endl;}
};

With the following main code:

int main()
{
Car A(1,200);
A.print();

Car B=A;
B.print();
}

When I run this code I get the following output:

1 - 200 - 0x14bdc20

1 - 200 - 0x14bdc20

This is also what I expected as the default assignment operator simply copies the values of id and data.

When I comment in the copy constructor and run the same code, I get the following output:

1 - 200 - 0x71bc20

1 - 200 - 0x71c050

Hence, the data pointer of B points to a new address. I do not quite understand why this happens. I thought the default assignment operator still would only copy the values from A and the only way to solve this was to overload the assignment operator. How is it the default assignment operator seems to use the copy constructor in this case?

CodePudding user response:

Lets consider what happens in the 2 cases individually. Also, note that there is difference between initialization and assignment in C . In particular, Car B=A; is copy-initialization and not copy-assignment.

Case 1

Here we consider the case where there is no user defined copy-constructor. That is, the case where you've commented the copy constructor.

class Car
{
private:
    int  id;
    int* data;
public:
    Car(int id, int data) : id(id) , data(new int(data)){}
    void print(){std::cout << id << " - " << *data << " - " << data << std::endl;}
};

In this case, the compiler implicitly synthesizes a copy-constructor. That copy constructor does memberwise copy of the data members. That is, it simply copies, the id and data data member from the passed argument.

This explains why you get the mentioned output. Because, they are nothing but a copy of the data members of the passed object. In particular, the data member data(is initialized) gets a copy of the data member data of the passed argument. That is, both the data members data of the passed argument as well as the current instance point to the same int object. Hence, the output is the same in this case.

Case 2

Here we consider the case where there is a user defined copy-constructor. That is, the case where you've commented out the copy constructor.

class Car
{
private:
    int  id;
    int* data;
public:
    Car(int id, int data) : id(id) , data(new int(data)){}
    Car(const Car& rhs) : id(rhs.id) , data(new int(*rhs.data)){}
    void print(){std::cout << id << " - " << *data << " - " << data << std::endl;}
};

In this case, the data member data points to the a newly created int object due to the expression data(new int(data)). Note that this is different from the case 1 because in case 1 the data member data simply gets a copy of the data member data of the passed object. That is, in case 1, both the data points to the same int. While in case 2, the data member data points to a separate int object created due to new int(data). Hence the output is different in this case.

  •  Tags:  
  • c
  • Related