Memory Management

Introduction

When using standard c pointers in c++, programmers must manually allocate and deallocate memory or programs will have memory leaks or pointers that point to nothing. A memory leak occurs when memory is allocated and never released. In cases of memory leak, the program will eventually run out of memory. Leaks occur when a member of a class is created and that member allocates memory, but has no way to release the memory when the member is no longer active.

To avoid memory leaks, every class that uses primitive c pointers must have a destructor to release that memory. Once you have a destructor, you must also create a copy constructor and assignment operator or you may be left with pointers that no longer point to data.

Destructors, Copy Constructors and Assignment Operators

To avoid problems with pointers, every class that contains a pointer it allocates, must also have a destructor, copy construct and assignment operator. The destructor deallocates memory when the pointer is no longer accessible (when members of the class go out of scope). The copy constructor and assignment operator make sure that when copies are made new memory allocated when we make a copy of a class member. If this is not done, a destructor call for one of the copies will destroy all copies and the original.

The Destructor

The destructor of a class MyClass is designated by ~MyClass. It is never (almost) call by a program directly, but called by the system when a member of MyClass is no longer in scope (end of a procedure or block in which the member is defined). If MyClass has a data member pointer , the destructor might be given as:

MyClass::~MyClass()
{
	delete pointer;
}
Look at the destructors used in my template linked list class. This is a more complex example since the list is responsible for more than one pointer. In the case of RcPointer there is only one pointer to delete but that pointer is only deleted when the count reaches 0.

The Copy Constructor

The copy constructor is another function that is often called by the system without the programmers explicite knowledge. It is used to create a copy of an object when that object is passed as a value parameter to a function. It initializes the parameter as a local variable in the function by copying the values from the variable passed to the function. The copy constructor always takes the form

MyClass(const MyClass&);
The form cannot be altered since the compiler will only accept this as the copy constructor. You may see how RcPointer declares the copy constructor by clicking here.

The Connection Between The Copy Constructor And The Destructor

The copy constructor and destructor are called at the opposite ends of a scope, so they work together. The constructor is used to keep track of the number of objects that uses the pointer. There must be one looking at the pointer before the copy constructor is called since the copy constructor is used to make a copy of an existing pointer. If that pointer is null, there is no need to count, but if it is not null, we increment the counter. The destructor calls free which is used to release memory in the assignment operator. In this case the function free decrements the number of items looking at the pointer. If that count reaches zero, then it deletes the storage.

RcPointer::RcPointer(const RcPointer &b)
		{if ((stor = b.stor)!=NULL) stor->rc++;}

RcPointer::~RcPointer(){free();}

void RcPointer::free()
		{if(stor && --stor->rc == 0) delete stor;}

The Assignment Operator

When you assign a member of a class with a pointer to another member of the class, you are creating another viewer of the first members pointer. At the same time there is one less viewer for the pointer stored in the left side member before the assignment. The fact that one more item is viewing the right side member object is taken care of by the first statement. The call to free reduces the count for the current data. Finally the pointer is reassign to the pointer from the right side of the assigment.

const RcPointer& operator = (const RcPointer &b)
	{
		if (b.stor) b.stor->rc++;
		free();
		stor = b.stor;
		return *this;
	}