CS105: Introduction to Computer Programming: C++

C++: Memory Management

The compiler automatically generates an assignment operator for any class that doesn't define it's own assignment operator. This default assignment operator simply does a member-wise copy of each of the pieces of data in the class. If a class has very simple data inside it, this default assignment operator works fine:

class Point2D {
public:
  Point2D( int x, int y ) {
    this->x = x;
    this->y = y;
  }
private:
  int x, y;
};

int main() {
  Point2D p1( 20, 10 );
  Point2D p2( 999999, 99999 );
  p1 = p2;                     // default assignment operator:
                               // fine, no problems
}

However, if our class allocates memory dynamically, then this default assignment operator will lead to disasterous results:

class Array {
public:
  Array( int n ) {
    size = n;
    data = new int[n];
  }
  ~Array() {
    delete[] data;
  }
private:
  int size;
  int *data;
};

int main() {
  Array arr1(10);
  Array arr2(10);
  arr1 = arr2;     // default assignment operator:
                   // DANGER! Leaked memory, double deletion!
}

After we assign arr1 = arr2, the data field of both arr1 and arr2 point to the same array of integers! This is certainly akward, since any change to one Array will affect the other. But even worse, when the it comes time to destroy the two Arrays, the computer will attempt to de-allocate the same memory twice. This will probably cause your code to crash rather dramatically.

The same problem occurs with the default copy constructor that the compiler generates for your class. It does a member-wise copy of the data in your class, which may not always be appropriate.

Here's an improved version of the Array class that has custom assignment operator and copy constructor:

Array.h
#ifndef ARRAY_H
#define ARRAY_H

#include <ostream>
using std::ostream;
#include <istream>
using std::istream;


class Array {
public:

  /**
   * Construct a new array of size N
   */
  Array( int n = 10 );
  /**
   * Overloaded copy constructor.
   */
  Array( const Array& arr );
  ~Array();

  /**
   * Overloaded assignment operator.
   */
  Array& operator=( const Array& rhs );

private:

  int* data;
  int size;
};

#endif
Array.cc
#include <iostream>
using std::cerr;
using std::endl;
#include "Array.h"


Array::Array( int n ) {
  size = n;
  data = new int[n];
}


Array::Array( const Array& arr ) {
  size = arr.size;
  data = new int[arr.size];
  for( int i = 0; i < arr.size; i++ ) {
    data[i] = arr.data[i];
  }
}


Array::~Array() {
  delete[] data;
}



Array& Array::operator=( const Array& rhs ) {
  if( this != &rhs ) {                    // check for self-assignment
    if( size != rhs.size ) {              // only re-allocate memory
      delete[] data;                      // if we need to
      data = new int[rhs.size];
      size = rhs.size;
    }
    for( int i = 0; i < rhs.size; i++ ) { // copy data from rhs to 
      data[i] = rhs.data[i];              // our array
    }
  }
  return *this;                           // allows chaining: a = b = c;
}