Search code examples
c++pointersconstructornew-operator

Pointer initialization is overriding the value


Dog.h

class Dog
{
public:
    int *pVal;
    Dog(int);
    ~Dog();
    static int GetVal(Dog d);
};

Dog.cpp

Dog::Dog(int val)
{
    pVal = new int;
    *pVal = val;
}

Dog::~Dog()
{
    delete pVal;
}

int Dog::GetVal(Dog d)
{
    return *(d.pVal);
}

Test

Dog fido(20);
CHECK(Dog::GetVal(fido) == 20);

Dog rex(21);
CHECK(Dog::GetVal(fido) == 20);
CHECK(Dog::GetVal(rex) == 21);

The first CHECK goes fine. However, as soon as I declare Dog rex(21), my fido object's pVal gets overridden by 21. By debugging, I have noticed that on calling new int in the constructor the pVal of rex gets the same memory address as the fido object's pVal. I tried a lot, but could not find anything.

What is the correct way of initializing the pointer and assigning the value to it?

Please help. Thank you in advance.


Solution

  • When you make this call:

    Dog::GetVal(fido);
    

    you make a copy of the Dog in the argument of GetVal. The default copy-constructor is invoked which only makes a shallow copy of pVal. So when the copy goes out of scope, the memory pointed at by pVal is deleted, which deletes the memory pointed at by fido.

    One fix would be to take a Dog& in GetVal, which avoids a copy.

    static int GetVal(Dog &d);
    

    A better option would be to provide a copy-constructor for your Dog, like this:

    Dog(Dog const & d) 
    { 
      pVal = new int{*(d.pVal)}; 
    }
    

    Here's a working demo.

    As to your observation:

    I have noticed that on calling new int in the constructor the pVal of rex gets the same memory address as the fido object's pVal.

    As mentioned above, by the time you call rex's constructor, the memory allocated for fido has already been released, so that same memory can be used for rex. (This is not guaranteed to happen of course).