Wednesday, February 27, 2013

Dynamic memory allocation with new and delete

There are many cases where it would be useful to be able to size or resize arrays while the program is being run. For example, we may want to use a string to hold someone’s name, but we do not know how long their name is until they enter it. Or we may want to read in a number of records from disk, but we don’t know in advance how many records there are. Or we may be creating a game, with a variable number of monsters chasing the player.
[http://efficientprograms.blogspot.in/]
If we have to declare the size of everything at compile time, the best we can do is try to make a guess the maximum number of variables we’ll need and hope that’s enough:
1
2
3
char szName[25]; // let's hope their name is less than 25 chars!
Record asRecordArray[500]; // let's hope there are less than 500 records!
Monster asMonsterArray[20]; // 20 monsters maximum
This is a poor solution for several reasons. First, it leads to wasted memory if the variables aren’t actually used. For example, if we allocate 25 chars for every name, but names on average are only 12 chars long, we’re allocating over twice what we really need! Second, it can lead to artificial limitations and/or buffer overflows. What happens when the user tries to read in 600 records from disk? Because we’ve only allocated 500 spaces, either we have to give the user an error, only read the first 500 records, or (in the worst case where we don’t handle this case at all), we overflow the record buffer and our program crashes.
Fortunately, these problems are easily solved via dynamic memory allocation. Dynamic memory allocation allows us to allocate memory of whatever size we want when we need it.


Dynamically allocating single variables
To allocate a single variable dynamically, we use the scalar (non-array) form of the new operator:
1
int *pnValue = new int; // dynamically allocate an integer
The new operator returns the address of the variable that has been allocated. This address can be stored in a pointer, and the pointer can then be dereferenced to access the variable.
1
2
int *pnValue = new int; // dynamically allocate an integer
*pnValue = 7; // assign 7 to this integer
When we are done with a dynamically allocated variable, we need to explicitly tell C++ to free the memory for reuse. This is done via the scalar (non-array) form of the delete operator:
1
2
delete pnValue; // unallocate memory assigned to pnValue
pnValue = 0;
Note that the delete operator does not delete the pointer — it deletes the memory that the pointer points to!
[http://efficientprograms.blogspot.in/]
Dynamically allocating arrays
Declaring arrays dynamically allows us to choose their size while the program is running. To allocate an array dynamically, we use the array form of new and delete (often called new[] and delete[]):
1
2
3
4
int nSize = 12;
int *pnArray = new int[nSize]; // note: nSize does not need to be constant!
pnArray[4] = 7;
delete[] pnArray;
Because we are allocating an array, C++ knows that it should use the array version of new instead of the scalar version of new. Essentially, the new[] operator is called, even though the [] isn’t placed next to the new keyword.
When deleting a dynamically allocated array, we have to use the array version of delete, which is delete[]. This tells the CPU that it needs to clean up multiple variables instead of a single variable.
Note that array access is done the same way with dynamically allocated arrays as with normal arrays. While this might look slightly funny, given that pnArray is explicitly declared as a pointer, remember that arrays are really just pointers in C++ anyway.
One of the most common mistakes that new programmers make when dealing with dynamic memory allocation is to use delete instead of delete[] when deleting a dynamically allocated array. Do not do this! Using the scalar version of delete on an array can cause data corruption or other problems.
[http://efficientprograms.blogspot.in/]

3 comments: