3

I'm new to this website, and to the programming world. So, please be patient with me :)

I read about the rule of three, and I understood how the Copy Constructor and the Assignment operator work. So I understood that, the default ones, provided by C++, provide a shallow-copy (or memberwise) of the objects.

My question is ... if the class has a member pointer (which points to dynamic allocated memory), the default Assignment Operator, will only copy the address held in the pointer from the original object to the pointer of the object is being assigned to. But won't this create a memory leak? For example, the followind code:

class GCharacter //Game Character
        {
            private:
                std::string name;
                int capacity;   //the capacity of our tool array
                int used;       //the nr of elements that we've actually used in that tool array
                std::string* toolHolder; //string pointer that will be able to reference our ToolArray;

            public:
                static const int DEFAULT_CAPACITY = 5;
            //Constructor 
                GCharacter(std::string n = "John", int cap = DEFAULT_CAPACITY) 
                :name(n), capacity(cap), used(0), toolHolder(new string[cap])
                {
                }
        }

    int main()
    {         GCharacter gc1("BoB", 5); 
              GCharacter gc2("Terry", 5); 
              gc2 = gc1;
              GCharacter gc3 = gc1;

              return 0;
    }

So, in this code, when gc1 is created, gc1.toolHolder holds the address of some dynamic allocated memory of 5 strings. Let's say, address 125. After this, gc2 is created and dynamic allocates memory for 5 strings, and let's say gc2.toolHolder holds the address 135.

The next line of code, calls the default assignment operator, and provides a shallow-copy from every member of gc1 to gc2. This means that now the pointer gc2.toolHolder also holds the address 125, and we no longer can access the memory at address 135. So the default assignment operator, in situations like these, creates memory leaks? ... or I understood something wrong??

Also, another question, in the case of the default Copy Constructor, because it is called only on objects that don't already exist, it means that gc3.toolHolder won't get the chance to allocate new memory, let's say, at address 145? It will just receive the address stored in gc1.toolHolder?

To try to be more specific... what I'm asking is if it's the same case as above, except we just have both pointers gc3.toolHolder and gc1.toolHolder, reference the same address 125, without gc3.toolHolder dynamic allocating new memory of 5 strings.

Long story short, when we instantiate a class that has a pointer member variable which points to dynamic allocated memory, will the default assignment operator cause a memory leak? and the default copy constructor share pointers to the same allocated memory?

Thank you for your time!

xPlay
  • 33
  • 3
  • 1
    Long story short, use an RAII container and you won't have these problems :p – chris Oct 20 '13 at 21:27
  • Yes, you would have memory leaks. As a good answer is already given by Daniel, I would like here only to suggest you using program `valgrind` to check memory leaks and similar problems. – Igor Popov Oct 20 '13 at 21:33

1 Answers1

2

The memory leak you have is the lack of a destructor which frees the memory allocated with new in the constructor, you need:

~GCharacter() { delete[] toolHolder; }

If you add this, you will see the second problem you have: The default generated copy-ctor and assignment just copy/assign the pointer, hence when you have a copy and both original and copy go out of scope, they will both try to delete the memory. This double-free is of course the much bigger problem than the memory leak as it will most likely corrupt the memory.

That said, you want to add your own copy-ctor and assignment operator and implement it correctly. In this case it means to allocate memory for the copy's toolHolder. Generally, read about the Rule of Five for when to implement which set of methods for your class.

Community
  • 1
  • 1
Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • I'd also suggest reading about the [Rule of Zero](http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html) on how to avoid having to worry about this ;-) – Philipp Lenk Oct 20 '13 at 21:34
  • Ok, got it. But even if I provide my own destructor ... the same questions is in my head. `gc2=gc1` will cause `gc2.toolHolder` to no longer be able to reference the memory it allocated. Isn't that a memory leak? BTW, I know it's better to provide our own copy-ctor and destructor and assign op, when dealing with dynamic memory ... but I'm trying to understand how the default ones work first. – xPlay Oct 20 '13 at 21:37
  • @xPlay Sure, therefore you need a correct assignment operator. But you can reduce complexity and the chances of having bugs by reusing a correct copy-ctor and swap. See [here](http://stackoverflow.com/questions/4421706). – Daniel Frey Oct 20 '13 at 21:39
  • @DanielFrey Thanks! :) It looks like I have to study those pages a bit, before I get back to this. – xPlay Oct 20 '13 at 21:51