Dynamic memory allocation

Objects that use dynamic memory allocation

Our own vector class

This program implements a small class that mimics the functionality of the Standard Library class vector.

Usage example:

  MyVector v; // creates an empty MyVector
  v.push_back(1);
  v.push_back(4);
  v.push_back(12);

  for(int i = 0; i < v.size(); i++) {
    cout << v.get(i) << ' ';       
  }
  cout << endl;

Implemention

To allow dynamically increasing the size of our vector, we store its elements in a dynamically allocated array, and when we storage has to be increased, we allocate another array of bigger size, copy all data in this new array, and then free the memory of the old array.

A important note about this implementation: If we copy an object of this class:

  MyVector v2 = v;

the object v2 is a “shallow” copy, because now both objects, the old one and the new one share the same pointer.

If one of the objects, v or v2, would like to increase the size of the heap-allocated array, the other one will not know about this change, so its pointer will be pointing to a region in the heap that became invalid. The program will misbehave and may eventually crash.

To resolve this issue, C++ let us redefine the assignment operator and the copy constructor, but we don’t do it here (see the book to read more about this issue).

#include <iostream>

using namespace std;

class MyVector {
  private:
    int cap;
    int used;
    int *arr; 
  public:
    
    MyVector();
    int size();
    int get(int i);
    void push_back(int v); 
};

int main() {

  MyVector v; // creates an empty MyVector
  v.push_back(1);
  v.push_back(4);
  v.push_back(12);

  for(int i = 0; i < v.size(); i++) {
    cout << v.get(i) << ' ';       
  }
  cout << endl;

  // copying this object makes a "shallow" copy, because both
  // objects, the old one and the new one will share the same pointer:
 
  // we make a copy anyway:
  MyVector v2 = v;
  
  // if one of the objects, v or v2, would like to increase the size of 
  // the heap-allocated array, the other one will not know about this change,
  // so its pointer will be pointing to a region in the heap that became invalid.
  // The program will misbehave and may eventually crash.

  for(int i = 0; i < v2.size(); i++) {
    cout << v2.get(i) << ' ';       
  }
  cout << endl;

}

MyVector :: MyVector () {
  cap = 1;
  used = 0;
  arr = new int[cap];
}

int MyVector :: size () {
  return used;
}

int MyVector :: get (int i) {
  return arr[i]; // does not check that we access a valid index
}

void MyVector :: push_back(int v) {
  if (used < cap) {
    // if the capacity is enough to add one more element
    arr[used] = v;
    used++;
  }
  else {

    int new_cap;
    new_cap = cap*2;
    int *new_arr = new int[new_cap];
    
    for (int i = 0; i < used; i++) {
      new_arr[i] = arr[i];
    }
    
    delete[] arr;
    arr = new_arr;
    cap = new_cap;

    arr[used] = v;
    used++;
  }
}


1 4 12 
1 4 12