1

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?

overhaul_
  • 71
  • 7
  • 5
    See [The rule of three/five/zero](https://en.cppreference.com/w/cpp/language/rule_of_three) (**Rule of three**) – David C. Rankin Aug 02 '20 at 18:13
  • Please clarify what you are asking by displaying the [output](http://coliru.stacked-crooked.com/a/1f7603ce240d15a5). Second, you should be more concerned with the crash at the end of the program. – PaulMcKenzie Aug 02 '20 at 18:19
  • @PaulMcKenzie I just edited the question with output – overhaul_ Aug 02 '20 at 18:29
  • Seems to be a few misunderstandings around pointers (no surprise). You don't change the pointer, you change what it is pointing to. So after the copy d1 and d2 have the same pointer value so if you change what that pointer is pointing to you see the change in both objects. If you actually changed the pointer, then you would not see that change in the other object. – john Aug 02 '20 at 18:29
  • @john I understood that but I also copied a & b to d2 why their values not changing? – overhaul_ Aug 02 '20 at 18:30
  • 3
    @overhaul_ Because you copied them. Obviously if you copy something and then change the original the copy doesn't change. – john Aug 02 '20 at 18:31
  • 1
    @overhaul_ That's the normal meaning of the word copy. – john Aug 02 '20 at 18:32
  • 3
    @overhaul_ Almost always when beginners fail to understand pointers it's because they mix up two different things, the value of the pointer, and the value of the thing it points to. That's what you are doing. Your code copies the pointer, but subsequently changes the value it is pointing to. That's why you see a difference in the behaviour of `a`, `d`, and `p`. – john Aug 02 '20 at 18:37
  • @john I totally got that now. Can you tell me about the crash error due to delete keyword? – overhaul_ Aug 02 '20 at 18:39
  • 2
    @overhaul_ Yes, because your two objects have the same pointer value, you end up deleteing the same pointer twice. And that often leads to a crash. To avoid that you should follow the reference that David C Rankin gives about the rule of three. – john Aug 02 '20 at 18:41
  • @overhaul_ Or maybe find a gentler introduction to it, that one is a bit dense. It is a very important subject. – john Aug 02 '20 at 18:42

1 Answers1

2

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.

reyad
  • 1,392
  • 2
  • 7
  • 12