Example of Memory Count in the Class Array

Example of problems with standard pointer type arrays

In this example we have a class that contains a pointer. When an instance of the class is created, the pointer has memory allocated, so the destructor must delete that memory.

class Wrong
{
public:
    Wrong(int size =0){if (size)_mem = new int [size]; else_mem= NULL;  _size = size;}
    ~Wrong(){ if ( _mem)delete [] _mem;}// the destructor
    int& operator [] (int i){return _mem[i];}
private:
    int *_mem;
    int _size; // how large is mem
}
In the following code, the function foo passes wrong as a value parameter, and upon return from the function, mem points to memory that has been deleted.
void foo(Wrong w)
{
    cout << w[1] << endl;
}
void main()
{
    Wrong wrong(5);
    wrong[0] = 1;
    wrong[1] = 2;
    wrong[2] = 3;
    foo(wrong);
    cout << wrong[1] << endl;
}
When the program tries to execute the output, there is a major error since wrong[1] now points to no allocated location. In the windows environment there error is not obvious until you trace the constructor calls. Then you will see the same memory released twice. This means that you can't be sure what will happen the second time you access wrong. You can run the complete version available here.

This error can be corrected by adding the copy constructor to the definition of Wrong. The copy constructor is called by c++ whenever a variable is passed by value to a function. The compiler provides a simple copy constructor which simply sets the copy's version of mem to the same pointer as the original variable's mem. When the destructor is called for the parameter as the program leaves the function call, the location deleted is that of the mem in the variable. To make sure the two versions have different pointers, you need to create the copy constructor. The compy constructor takes the form
X(const X &)
in this case:
Wrong ( const Wrong &w)

This copy constructor first allocates new memory, then copies the data from the old variable:

Wrong::Wrong( const Wrong &w)
{
    _mem = new int [w._size];
    _size = w._size;
    for ( int i = 0; i < _size; i++)
        _mem[i] = w._mem[i];
}

Using a Counted Pointer

Instead of using the primitive c array, we should have used a c++ arrary such as that defined in darray.h. This type of container class has a built-in memory management, so there is no need to create either the destructor or copy constructor in the class Right defined here.

class Right
{
public:
    Right(int size=0) :_mem(n){}
private:
    Array _mem;
};
If wrong is replaced by right in our example, then the schematic below shows how the copy constructor for array alters the access count.
void main()
{
    Right right(5);
  
right[0] = 1;
right[1] = 2;
right[2] = 3;
foo(right);
cout << right[1] << endl;
}
When the end of the program is reached, and right goes out of scope, and the count is decremented to 0. When the count is zero the memory is released.