Memory allocation and deallocation (in relation to OOP)

If you have dynamic memory allocation associated with your class (e.g., a data member is a pointer), then you must write a copy constructor, a destructor, and an overloaded assignment. If your class doesn't have dynamic memory, the default copy constructor and assignment operator which do a memberwise copy are used. Since you have no dynamically allocated memory, you don't need a destructor.

Copy constructor
The copy constructor is called in three ways:
  1. Directly. For example, the object x is instantiated. The object y is instantiated as a copy of x using the copy constructor.
         Array x(20);
         Array y(x);
      
  2. When an object is returned in a function, the copy constructor is called to do the copying back from the function to the caller. For example, operator+ of the Rational class returns a Rational object.
         Rational x(1,2), y(3,4), z;
         z = x + y;
      
  3. When an object is passed by value to a function, the copy constructor is called to do the copying. For example, the Array object must be copied. Memory is allocated for the int array and the contents are copied.
         main:
            Array x(20);
            doSomething(x);
    
         function:
            void doSomething(Array x) { ... }
      
In the last example, it is inefficient to do all the work of allocating memory and copying values (suppose the int array had a million elements), which is why we typically simulate pass by value:
     void doSomething(const Array& x) { ... }
  
Assignment (operator=)
The default operator= also does a memberwise copy, so if you want operator= to work properly, meaning each object has its own, separate memory, then you must write it. It will look similar to the copy constructor, but it will check for self assignment and then deallocate the old memory before allocating new memory. See the operator= of Array for an example.

If you don't want to allow assignment in a class, then make operator= private.

Destructor
While the compiler will deallocate memory for any data members, C++ does not have garbage collection like in Java, so you must deallocate any memory you (the programmer) allocated (when you use new) that is associated with the object. This is done in the destructor, which is called automatically when the object goes out of scope. If you don't deallocate this memory, you have a memory leak (memory that was allocated, but never deallocated, and therefore can't be used by your program in the future).

Memory allocation/deallocation rule: IF YOU ALLOCATE IT (use a new), YOU MUST DEALLOCATE IT (delete it)!

See the destructor of Array for an example.