Search code examples
c++copy-constructordeep-copy

Copy constructor and dynamic memory


I am a beginner in programming and I am learning about copy constructors. From different sources I can see that copy constructors are useful if I want to "deep copy" a class object so the new object's pointer members will point to new memory locations.

My question is, what is the advantage of defining the copy constructor as I do in class CopyCat in my example, if I get the same result with an empty copy constructor (as in class EmptyCat)?

My second question is, why do class Cat and class EmptyCat work differently? The only difference between them is that I define an empty copy constructor in EmptyCat. But as I run the program I can see that in EmptyCat after the copying the pointer member points to a new location while in class Cat it works as a shallow copy.

#include "iostream"

class Cat
{
  public:
    void GetMem() { std::cout << itsAge << "\n"; }
  private:
    int * itsAge = new int;
};

class EmptyCat
{
  public:
    EmptyCat() {}
    ~EmptyCat() {}
    EmptyCat(EmptyCat&obj) {}
    void GetMem() { std::cout << itsAge << "\n"; }
  private:
    int * itsAge = new int;
};

class CopyCat
{
  public:
    CopyCat() {}
    ~CopyCat() {}
    CopyCat(CopyCat&obj);
    int GetAge() { return *itsAge; }
    void GetMem() { std::cout << itsAge << "\n"; }
  private:
    int * itsAge = new int;
};

CopyCat::CopyCat(CopyCat & obj)
{
    itsAge = new int;
    *itsAge = obj.GetAge();
}

int main()
{
    Cat Garfield;
    Cat Kitty(Garfield);

    std::cout << "Memory addresses for the objects' <itsAge> member:" << std::endl;
    std::cout << "Garfield and Kitty (Class Cat):" << std::endl;
    Garfield.GetMem();
    Kitty.GetMem();

    EmptyCat Meow;
    EmptyCat Purr(Meow);

    std::cout << std::endl << "Meow and Purr (Class EmptyCat):" << std::endl;
    Meow.GetMem();
    Purr.GetMem();

    CopyCat Fluffy;
    CopyCat Felix(Fluffy);

    std::cout << std::endl << "Fluffy and Felix (Class CopyCat):" << std::endl;
    Fluffy.GetMem();
    Felix.GetMem();

    system("pause");
    return 0;
}

If I run the program I get this:

Memory addresses for the objects' <itsAge> member:
Garfield and Kitty (Class Cat):
00BBDA60
00BBDA60

Meow and Purr (Class EmptyCat):
00BB46A0
00BB8280

Fluffy and Felix (Class CopyCat):
00BB82B0
00BBE8A0
Press any key to continue . . .

Solution

  • My question is, what is the advantage of defining the copy constructor as I do in class CopyCat in my example, if I get the same result with an empty copy constructor (as in class EmptyCat)?

    You don't get the same result. CopyCat allocates new memory and copies the value from the old class. The EmptyCat just allocates new memory, but does not copy the value.

    My second question is, why do class Cat and class EmptyCat work differently? The only difference between them is that I define an empty copy constructor in EmptyCat. But as I run the program I can see that in EmptyCat after the copying the pointer member points to a new location while in class Cat it works as a shallow copy.

    In Cat you haven't declared a copy constructor, so the compiler will generate one when needed. The default copy constructor does a member-wise copy from the original. In your case, this will copy the pointer (so that it stores the same address as the original).

    In the EmptyCat you have a user defined copy constructor. But as that one doesn't handle the pointer member, its default value will be used.

    int * itsAge = new int;
    

    This is what allocates a new int and gets you a different pointer value.