Home Page
The Basics
Arrays
Classes
Abstract Data Types

Operator Overloading
Lists
C++ Style Strings
Linked Lists
Stacks and Queues
Variable Data Types
Templates
Sorting
DMA

Dynamic Memory Allocation
DMA allocates memory for use in program at the time the program runs.  An example of this is a word processor, which allocates memory "on the fly".

Routines for allocating memory are in:
     <cstring>  // contains info on memcpy
     <cstdlib>  // info on malloc and free

malloc:
Malloc in C stands for memory allocation.  It takes one argument, which is an integer representing the number of bytes you want to allocate, and returns a pointer to a void.
     void * malloc (int n);

Example of use:

     int *p = 0;     // initializes pointer to 0

     p = (int *) malloc(sizeof(int))     // sizeof assures correct number of bytes

now you can use like…
     *p = 7;

** IMPORTANT**
Whatever you allocate, you are responsible and MUST free up when done using it to avoid memory leaks.  This is done using the keyword free.
free:
free will return memory allocated using malloc.  An example of it's use follows.
     free(p);          //this free's up memory allocated for *p

Note:  If this memory was allocated inside a function and was not freed up before you left function, you would most likely have a memory leak.  When you leave the function you lose your variable but then you have allocated memory that is not addressable from anywhere.

What about memory for more than one thing??  Like an array of integers?  Let's try for 100 integers and only 100 integers…

int ar = 0;

int size;
.
.
.
size = 100;
ar = (int ) malloc (sizeof (int)  *size);

This will allocate dynamic memory for 100 integers.  Now you can take this pointer and reference it as an array.

Example:
cout << ar[7];
free (ar);

There is more information on "on the fly" memory allocation in the man pages under realloc.

Problem:

Malloc and free have one problem.  Malloc does not initialize allocated memory.  This is why C++ came up with a new way to allocate memory using the keyword new.  This is the method we will use in this class from now on.

new:
new is an operator which takes on the right side, type of memory to allocate…

Example:
int *p;
p = new int;

notice that you didn't need anything like sizeof. The compiler takes care of this.  Also, you don't have to do casting because it will also check for that.  Another added bonus is that new will allocate memory and call the constructor to initialize it (yippee!).

Example:
class Widget
{
};
Widget *w, *v;

w = (Widget *) malloc (sizeof(Widget));     // this is the C way
v = new Widget;                             // this is the way for C++

It's much easier AND calls the constructor.

Freeing up the memory is now replaces the command free, with the keyword delete.
delete:
Delete takes a pointer to the type to free up memory for.

free (w);     // this is what you did in C using malloc
delete v;     // this is what C++ uses when using new

IMPORTANT:
Under no circumstances can you use free to replace memory that was allocated using new or delete for memory allocated using malloc.  You can use either or both in C++ but you must use with corresponding types.

new and delete are only for C++ and are keywords so you don't have to "include" anything.

Example:  now allocate an array of 10 Widgets…

Widget *x_ar;

x_ar = new Widget[10];     

This allocates memory and calls constructor for all 10 Widgets. But there is one minor wrinkle.  When you release memory for an array of Widgets it is slightly different.

delete [] x_ar;

What would happen if you were to code…

p = new int[10];
delete p;      // instead of delete [] p

or…

q = new int;
delete [] q;  // instead of delete q

not much at run time but it will catch up with you so make sure you use proper delete operator.

One more thing about the new constructor and taking arguments.

Example: to dynamically allocate memory for a complex variable…

complex *c, *d, *e;

c = new complex;
d = new complex(2.7);
e = new complex(3, 1.7);

*** you can call whatever constructor you want BUT you can't do it for arrays.

arrays will always call the default constructor so always make default constructor if you could possibly use an array in the class.

New Implementation of String class Using DMA:

if we were to use the String class we created earlier and ran over the size of memory that was set aside for the array we would be toast.  So…let's create a new String class using DMA.

   class String
{
private:
    char *data;
    int len;

public:
    String();
    String(const char *);       // initialize from  C style string
    .
    .
    .
};
/*******************************************************/
String::String()
{
     len = 0;
     data = 0;     // makes sure it doesn't point to something important
}

/*******************************************************/
String::String(const char *s)
{
     len = s.len;
     data = new char[len]

// loop to copy all characters from s into data
     for (int i=0; i<len; i++)
          data[i] = s[i];
}

Tip:  Look into memcpy in libraries manual for more information

But wait a minute… How are you supposed to free up memory here??

String s = "disaster";
when it's created you have…

*s
len = 11
à
d
i
s
a
s
t
e
r

when the function ends it will free up *s but it will now free up the memory used by the string.  The solution for this is to use a destructor.

destructor:
in addition to the constructor in the class declaration you need to include…

~String();

and in the .C file you need the method:

String::~String()
{
     delete [] data;   // use this way to delete memory for array of char's
}

the destructor will be called automatically so you don't need to worry about calling but you must have it or you will run into big problems.

delete will automatically call the destructor before it frees up memory.  This is why we need to delete arrays with delete [] ptr.  It will call destructor on every single position in the array and free them up.

now we will make a slight change from the String class to a Vector class (very, very similar).

Vectors:  (one-dimensional array of numbers)

say you have an array and call a function named void func()

void func()
{
     p = new Vector[10];  // allocates memory for array of 10 Vectors
}

This will call constructor and points to the beginning of the array.  now you can create DMA for each instance of that array.

*p

       



               
               
               
               

at the end of the function you will type

delete[] p;

This calls the destructor on each Vector element of p then it will free up the memory.

Operator overloading for arrays:
 1st - []
takes two arguments
array to be indexed (outside the brackets)
integer indicating number of element to access)

in Vector class you have…
2nd - double & operator [](int)

in the .C file you would have

double & Vector::operator [](int)
{
     return data[i];
}

say that you want to create a constant Vector v2…

Vector v1;
const Vector v2;

cout << v2[3];
v1[5] = -1;   // won't work - problem with l-value

if you change to 2nd way you could assign to v1[5] but now cout << v2[3] won't work because it's retreiving a reference which is an l-value.  So… we have to create another operator subscript.


double & operator [] (int i);    // can change
double operator [](int i)const;  // current instance will remain constant

the first is not a constant instance but the second is.  The second method overload is the same as the first but is returning a double.

we can use the first one to say   v1[5] = -1;

how does this effect arrays of vectors?

Vector ar[7];

ar [3][5];  

This gets element 5 out of an array of 3 Vectors.  Not to be confused with C++ vectors so watch out!

Let's implement:   (in Vector.h)

#ifndef VECTOR_H
.
.
.
class Vector
{
    int len
    double *data;
public:
    Vector();
    .
    .
    double & operator [] (int i);
    double operator [] (int i)const;
    ~Vector();
    friend ostream & operator <<(ostream &, const Vector &);
};

now in Vector.C

Vector::Vector()
{
    data = 0;
    len = 0;
}

/*************************************/
Vector::Vector(const double *data, int size)
{
    len = size;
    data = new double[size];

    for(int i=0; i<len; i++)
        data[i] = d[i];
}

/*************************************/
Vector::~Vector()
{
    delete [] data;
}/*****************************************/
ostream & operator << (ostream & ostr, const Vector &v)
{
    for(int i=0; i<v.len; i++)
        ostr << v.data[i] << "  ";
    return ostr;
}

/******************************************/
double Vector:: operator [](int index)
{
    return data[index];
}



Now the driver program so far…

#include <iostream>
#include "Vector.h"

double data[] = {…some numbers};

int main()
{
    Vector v1;
    Vector v2(data, sizeof(data);  // gives size of (double)

    cout << v2[2];
    cout << "*" << v1 << "*" << v2;

    return (0);
}

say you have a function that takes a vector..

function (Vector v)
{
}

in the main ()…
Vector v1;

function (v1);

v1
à
DMA memory

it's not a reference so it's passed by copy.  In calling the function it sets up memory for v including the value of the pointer so v points to the DMA memory of v1

v1
à
DMA memory

v

When it is done with the function it calls destructor on v which kills memory allocated for v1.  Now v1 points to something that doesn't exist.  How can we fix this problem??  With the copy constructor.





Copy Constructor:

in class definition..

Vector(const Vector &);  // what's different is the assignments

this is so that everything gets copied in, including DMA issues.  Implement it in the .C file like this

Vector::Vector (const Vector &v)
// const because you're not changing value passed in
{
    len = v.len;
    data = new double[len];
    for (int i=0;  i<len;  i++)
        data[i] = v.data[i];
}

When is this called??  Three different places.

in variable instance creation when initializing from same type.
example:
     Vector v1;
     Vector v2 = v1;

copying variables of arguments
example:
     func(Vector v);

copying return values
example:
     Vector function ( …)
     {
     .
     .
     .
     return result;
}
this will copy into temporary location then cleanup is done then it will return value to variable.  Most compilers will copy straight into variable if they are smart enough.

now look at this substitution…

Vector v1, v2;

v1
à
DMA memory


v2
à
DMA memory

v1 = v2;

what will happen?? now v1 points to v2.

v1
à
DMA memory


v2
à
DMA memory




Problems:
float ar1[] = {3.0, 5.0, -1.2};
float ar2[] = {0.0, -7.5};

Vector v1 (ar1, 3);
Vector v2 (ar2, 2);

in memory would look like…

v1
len = 3
à
3.0
5.0
-1.2

v2
len = 2
à
0.0
-7.5
 

when you execute the statement…
     v1 = v2;

there are two problems:

there is a memory leak
you have changed the value of where it points to.