// Example illusrating dynamic memory management
// ECE2036
// George F. Riley, Georgia Tech, Fall 2012
#include
using namespace std; // We will discuss namespaces later
class A {
public:
A(); // Default Coonstructor
A(int i); // Int Coonstructor
A(const A& a0); // Copy constructor
~A(); // Destructor
public:
int a; // Member variable
};
// Implement the constructors
A::A() : a(0)
{ // Default Constructor
cout << "Hello from A Default Constructor, a is " << a << endl;
}
A::A(int a0) : a(a0)
{ // Default Constructor
cout << "Hello from A int Constructor, a is " << a << endl;
}
A::A(const A& a0) : a(a0.a)
{ // Default Constructor
cout << "Hello from A Copy Constructor, a is " << a << endl;
}
A::~A()
{ // Destructor
cout << "Hello from A destructor, a is " << a << endl;
}
// Define a global array of A objects.
// We already know that the compiler is responsible for finding
// memory, calling the constructor(s) prior to entering "main"
// and calling the destructors after exiting "main"
A globalArrayA[10]; // How many constructors?
// A subroutine that allocates an array dynamically and does
// not delete it.
void Sub1(int numberObjects)
{
// Allocate an array of A objects using new
cout << "In sub1, allocating \"numberObjects\" A objects with new" << endl;
A* pA = new A[numberObjects];
// Since we used the default constructor, all a's should be
// initialized to zero.
cout << "In sub1, printing object values" << endl;
for (int i = 0; i < numberObjects; ++i)
{
cout << "pA[" << i << "] is " << pA[i].a << endl;
}
// Now we exit without doing anything with pA (no delete).
// What happens here?
}
A* Sub2(int numberObjects)
{
// Allocate an array of A objects using new
cout << "In sub2, allocating \"numberObjects\" A objects with new" << endl;
A* pA = new A[numberObjects];
// Initialize the pA.a members to non-default values
for (int i = 0; i < numberObjects; ++i)
{
pA[i].a = i * 100;
}
// Now we exit by returning the pA pointer to the caller.
// but not "deleting" it. Is this a memory leak?
return pA;
}
int main()
{ // Illustrate the use of dynamic memory
// First some simple local variables. In all cases, the
// memory to hold the variable is automatically allocated on
// the stack, and the constructor is called. When the function
// exits (in this case "main" exiting, the destructor is called
// then the memory is "deleted"
cout << "Entering main" << endl;
A a0(1); // Single A object on stack with "int" constructor
cout << "Creating local aArray[20]" << endl;
A aArray[20]; // Array of 20 A's, using default constructor
// Unfortunately, there is no easy syntax for creating an array of
// "k" A object with non-default constructor, although it can be
// done. We will discuss array initialization later.
//A aArray2[10](10); // Won't compile
// So far we create a global array of A objects "globalArrayA"
// and a local array "aArray". The problem is that in both cases
// we have to know AT COMPILE TIME the size of the array. What
// we really want is a way to decide AT RUN TIME how big an array
// should be. This can by done by using the HEAP.
// For this simple example, we just use the constant 8, but let's
// assume that "arraySize" is somehow determined at run time and
// can be any reasonable value.
int arraySize = 8;
cout << "Allocating pointerToArray" << endl;
A* pointerToArray = new A[arraySize];
// Note the use of the "new" operator. This does three separate and
// distinct things:
// 1) Find enough contiguous memory for "arraySize" objects of class A
// 2) Call the default constructor on each of the new A objects
// 3) Return a POINTER to the allocated memory
// Let's initialize the new array to some value
for (int i = 0; i < arraySize; ++i)
{
pointerToArray[i].a = i;
}
// And print them out
for (int i = 0; i < arraySize; ++i)
{
cout << "element " << i << " is " << pointerToArray[i].a << endl;
}
// Since we explicitly allocated memory for "pointerToArray" with new,
// we must explicitly destroy the memory with "delete". And since
// we allocated an array of objects, we need a special form of
// delete as shown.
cout << "Deleting pointerToA" << endl;
delete [] pointerToArray;
// We can also use "new" to allocate a single object. In this case
// we can specify a non-default constructor
cout << "Allocating single A object with int constructor" << endl;
A* pA = new A(200); // Int constructor
cout << "pA.a is " << pA->a << endl;
// And we should return the memory with "delete".
cout << "Deleting pA" << endl;
delete pA;
// Call a subroutine to illustrate a "memory leak".
cout << "Calling sub1" << endl;
Sub1(5);
// Call a subroutine illustrating a functino returning a pointer
// to a dynamically allocated array
cout << "Calling sub2 to allocate an array " << endl;
A* pA2 = Sub2(10);
// Print out the returned pA2 array
cout << "Printing pA2 (return from Sub2)" << endl;
for (int i = 0; i < 10; ++i)
{
cout << "pA2[" << i << "] = " << pA2[i].a << endl;
}
// We need to return the memory for pA2 when we are done with it.
cout << "Deleting pA2" << endl;
delete [] pA2;
cout << "Exiting Main" << endl;
}