Copy constructor + Shallow & deep copy

overhaul_

I wanted to ask that when I don't write any copy constructor explicitly so the compiler automatically generates the copy constructor which performs shallow copy by default right? So in the main() program when I changed the values of integers a, b and pointer p only the value of p changed and values of a and b remain unchanged in the copied object. Why the values of a & b didn't change too? My code is:

#include <iostream>
#include <string.h>
using namespace std;

class Dummy {
    private:

        int a, b;
        int *p;
    public:
        Dummy() {
            p = new int;
        }
        void setData(int x, int y, int z) {
            a = x;
            b = y;
            *p = z;

        }
        void showData() {
            cout << "a = " << a << " b = " << b;
            cout << " p = " << *p << endl;
        }

        ~Dummy() {
            delete p;
        }
};

int main() {

    Dummy d1;
    d1.setData(3, 4, 5);
    Dummy d2 = d1;
    d1.showData();
    d2.showData();
    d1.setData(6, 7, 8);
    d1.showData();
    d2.showData();
    return 0;
}

The output of my program is:

a = 3 b = 4 p = 5
a = 3 b = 4 p = 5
a = 6 b = 7 p = 8
a = 3 b = 4 p = 8

What I'm saying is while the pointer of object d2 changed when I changed the values of object d1 then why didn't the values of a & b of object d2 changed too?

Also I'm using delete keyword in the destructor to delete the dynamically allocated pointer:

~Dummy() {
            delete p;
        }

But it's crashing my program instead. Why is that?

reyad

You've totally got it wrong - The idea of shallow copy. Actually, c++ does not have anything called deep copy built into itself. So, calling something shallow copy is a bit wrong. And just the use of these words shallow copy creates a lot of confusion too.

Now, let me explain, what happens when cpp performs initialization using assignment. cpp or c(while copying struct) has a concept called bitwise copy. In this concept, all the member variables of one object(struct object/class object - you can say either) is identically copied to another object. Now, it's totally wrong idea that, both objects point to same memory location. In actual, both object has their own memory location and of course, their variables occupy different memory spaces. For you, I have write some tests regarding memory. You would understand perfectly, if you just see the test and it's output:

#include <iostream>
#include <string.h>

using namespace std;


class Dummy {
    int a, b;
    int *p;
public:
    Dummy() {
        p = new int;
    }
    void setData(int x, int y, int z) {
        a = x;
        b = y;
        *p = z;
    }
    void showData() {
        cout << "a = " << a << " b = " << b;
        cout << " p = " << *p << endl;
        cout << endl; // an extra new line for readability of output
    }
    void showMemory() {
        cout << "addr(a) = " << &a << " addr(b) = " << &b;
        cout << " addr(p) = " << &p << endl;
    }
    ~Dummy() {
        *p = 100;
        delete p;
    }
};
// testing memory
void memoryTest() {
    cout << "testing d1:" << endl;

    Dummy d1;
    d1.setData(3, 4, 5);
    
    cout << "addr(d1) = " << &d1 << endl;
    d1.showMemory();
    cout << endl ;


    cout << "testing d2:" << endl;

    Dummy d2 = d1;
    cout << "addr(d2) = " << &d2 << endl;
    d2.showMemory();
}

int main() {
    // memoryTest
    memoryTest();

    return 0;
}

And the output of the test was:

testing d1:
addr(d1) = 0x6dfed4
addr(a) = 0x6dfed4 addr(b) = 0x6dfed8 addr(p) = 0x6dfedc

testing d2:
addr(d2) = 0x6dfec8
addr(a) = 0x6dfec8 addr(b) = 0x6dfecc addr(p) = 0x6dfed0

This clearly shows that, the memory occupied by those two objects d1 and d2 are totally different.

  1. Now, you may have another question remain: Then, why, when i write *p=8, it affects both d1 and d2?:

When you assign, Dummy d2 = d1;, we may say something happended like below(though, it's not actually happen when bitwise copy is applied, it's just for clarity):

d2.p = d1.p

So, we know that, d1.p and d2.p contains the same memory location(note: d1.p is a pointer. so, it does not contain any integer, rather it contains memory address of an int).

So, when you write *p = 8, you are telling the program to go to the memory location targeted by p and change the value of that memory location to 8.(note, here, you didn't change the content of d1.p, d1.p still contains the same memory location. rather, you just changed that memory location's content from 5 to 8). That's why when you call d2.p, you get the changed value. cause, d2.p contains the same memory location as d1.p.

  1. Now, there may have one more question: Why your code crashes when you freed p in destructor?:

Now, let me first ask you, can you free a memory what is already freed. You can write the code, but the behavior is undefined. It may crashes your program or it may do nothing.

Well, in Dummy destructor you've written delete p;. Now, either d2 or d1 would be destroyed first. Let's assume, d2 is destroyed first. So, when d2's destroyer is called, p is freed. Then, d1's destroyer will be called and it'll also try to free p. But p is already freed. And in your case, the program meets a crash for this reason.

Hope, everything is clear to you now.

If anything is not clear about what I've described above, then ask questions, I will try my best to answer them too.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related