Copying class objects

Hello,

I had a question re. copying of pre-defined types(int, doubles etc..) and user-defined types(classes for example..)

If we have the following code:

1
2
3
4
5
int a = 10; //a is assigned the value 10 and is stored at a memory location
{
int b = a; //b is assigned the same value as a and stored at another memory location
} //b is destroyed when it leaves scope, whereas a remains.
cout << &a; //we get the address where a is stored.  


But what happens if we have a user defined type and do the same thing, where we haven't implemented a copy constructor? What will happen?
Last edited on
It works the same for user-defined types. If you don't write a copy constructor for your class the compiler will generate one for you.
Alright, thx. And the compiler generates a copy constructor using shallow copy, right?

And why do we want to implement our own copy constructor using deep copy?
Alright, thx. And the compiler generates a copy constructor using shallow copy, right?

It will just copy each data member without doing anything special. If the member is a pointer it will just copy the pointer as-is without touching the object that is pointed to. If the member is a class object it will call the copy constructor.

And why do we want to implement our own copy constructor using deep copy?

It's mostly when the class contains a pointer that you need to implement your own copy constructor. If the pointer points to some dynamically allocated object that you delete in the destructor you don't want to end up with two objects with pointers to the same dynamically allocated object because that could lead to the dynamically allocated object being deleted twice (which is not allowed) or one object might try to use the dynamically allocated object after it has been deleted by the other object's destructor. For that reason you either want to disable the copy constructor or implement it in such a way that the dynamically allocated object is copied so that each object has its own copy.

Related to this is the rule of three: https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
Last edited on
Thanks. I made a simple test to make sure I understood the concept.

header file:
1
2
3
4
5
6
7
8
9
10
11
class MyClass {
private:
    int* myNumber;
public:
    MyClass(int myValue);
    void setMyValue(int myValue);
    int getMyValue() const;
    ~MyClass();
};

ostream& operator<<(ostream& os, const MyClass& mc);


Implementation file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MyClass::MyClass(int myValue) {
    myNumber = new int;
    *myNumber = myValue;
}

MyClass::~MyClass() {
    delete myNumber;
    myNumber = nullptr;
}

void MyClass::setMyValue(int myValue) {
    *myNumber = myValue;
}

int MyClass::getMyValue() const {
    return *myNumber;
}

ostream& operator<<(ostream& os, const MyClass& mc) {
    os << mc.getMyValue();
    return os;
}


Now, when we create two instances of the class from main (I put in some comments in the code - is the reasoning correct?)
1
2
3
4
5
6
7
8
9
10
MyClass n1{10}; //Creating a MyClass-object n1 which is stored somewhere in memory
    cout << n1;
    
    MyClass n2{20}; //Same as above.
    
    n2 = n1; //Copying the data-members of n1. i.e. the myNumber pointer of n2 now holds the SAME address in memory as the n1 myNumber pointer.
    n1.setMyValue(40); //setting the value at the pointer address equal to 40.
    cout << n2; //returns 40, as all changes made to n1 will be reflected in n2 as it holds the same address.

  

The program finally crashes when exiting main as we are trying to free the same memory twice, right?
The program finally crashes when exiting main as we are trying to free the same memory twice, right?

Correct. The compiler provided copy constructor did a shallow copy which means it copied the myNumber pointer verbatim.

At the end of the program, n1 and n2's destructors are called. Because n1's destructor gets called first, it frees its memory. When n2's destructur gets called, it tries to free the same memory which has already been released by n1.
Last edited on
Yep, that is correct.
self defense tip -- every call to delete should null the pointer:

delete [] ptr;
ptr = nullptr;

delete of null does nothing / harmless. delete of bad address is not so good.
but 2 objects with the same pointer inside is confusing and difficult to deal with on many levels. I advise avoidance, and if you can't, extreme care is needed.
Last edited on
Thx.

Why delete [] ptr tho and not delete ptr, given that ptr in this case holds an int and not an array?
it was just an example, I didnt even look at your variable names. if its 1 delete, if its a block []. Seems like [] always works but maybe that is only true if you allocate 1 via [1]? I can't think of the last time I allocated 1 of something... having a moment thinking thru it.. lol

the point is the null assignment, not the delete syntax.
Last edited on
Topic archived. No new replies allowed.