Memory Management New and Delete in C++

Memory Management : We’ve seen many examples where arrays are used to set aside memory. The statement int arr1[100]; reserves memory for 100 integers.

Arrays are a useful approach to data storage, but they have a serious drawback: We must know at the time we write the program how big the array will be. We can’t wait until the program is running to specify the array size. The following approach won’t work:

cin >> size; // get size from user
int arr[size]; // error; array size must be a constant

The compiler requires the array size to be a constant.

But in many situations we don’t know how much memory we need until runtime. We might want to store a string that was typed in by the user, for example. In this situation we can define an array sized to hold the largest string we expect, but this wastes memory.

The new Operator

C++ provides a different approach to obtaining blocks of memory: the new operator. This versatile  operator obtains memory from the operating system and returns a pointer to its starting point. The NEWINTRO example shows how new is used:

// newintro.cpp
// introduces operator new
#include  <iostream>
#include  <cstring>     //for strlen
using namespace std;
int main()
{
char* str = “Idle hands are the devil’s workshop.”;
int len = strlen(str); //get length of str
char* ptr; //make a pointer to char
ptr = new char[len+1]; //set aside memory: string + ‘\0’
strcpy(ptr, str); //copy str to new memory area ptr
cout << “ptr=” << ptr << endl; //show that ptr is now in str
delete[] ptr; //release ptr’s memory
return 0;
}

The expression
ptr = new char[len+1];

returns a pointer to a section of memory just large enough to hold the string str, whose length len we found with the strlen() library function, plus an extra byte for the null character ‘\0’ at the end of the string. Figure shows the syntax of a statement using the new operator. Remember to use brackets around the size; the compiler won’t object if you mistakenly use parentheses, but the results will be incorrect.

Syntax of the new operator

In NEWINTRO we use strcpy() to copy string str to the newly created memory area pointed to by ptr. Since we made this area equal in size to the length of str, the string fits exactly. The output of NEWINTRO is

ptr=Idle hands are the devil’s workshop.

C programmers will recognize that new plays a role similar to the malloc() family of library functions. The new approach is superior in that it returns a pointer to the appropriate data type, while malloc()’s pointer must be cast to the appropriate type. There are other advantages as well.

C programmers may wonder whether there is a C++ equivalent to realloc() for changing the size of memory that has already been reallocated. Sorry, there’s no renew in C++. You’ll need to fall back on the ploy of creating a larger (or smaller) space with new, and copying your data from the old area to the new one.

The delete Operator

If your program reserves many chunks of memory using new, eventually all the available memory will be reserved and the system will crash. To ensure safe and efficient use of memory, the new operator is matched by a corresponding delete operator that returns memory to the operating system. In NEWINTRO the statement

delete[] ptr;

returns to the system whatever memory was pointed to by ptr.

Actually, there is no need for this operator in NEWINTRO, since memory is automatically returned when the program terminates. However, suppose you use new in a function. If the function uses a local variable as a pointer to this memory, the pointer will be destroyed when the function terminates, but the memory will be left as an orphan, taking up space that is inaccessible to the rest of the program. Thus it is always good practice, and often essential, to delete memory when you’re through with it.

Deleting the memory doesn’t delete the pointer that points to it (str in NEWINTRO), and doesn’t change the address value in the pointer. However, this address is no longer valid; the memory it points to may be changed to something entirely different. Be careful that you don’t use pointers to memory that has been deleted.

The brackets following delete indicate that we’re deleting an array. If you create a single object with new, you don’t need the brackets when you delete it.

ptr = new SomeClass; // allocate a single object
. . .
delete ptr; // no brackets following delete

However, don’t forget the brackets when deleting arrays of objects. Using them ensures that all the members of the array are deleted, and that the destructor is called for each one.

A String Class Using new

The new operator often appears in constructors. As an example, we’ll modify the String class, last seen in examples such as STRPLUS, “Operator Overloading”. You may recall that a potential defect of that class was that all String objects occupied the same fixed amount of memory management. A string shorter than this fixed length wasted memory, and a longer string if one were mistakenly generated could crash the system by extending beyond the end of the array. Our next example uses new to obtain exactly the right amount of memory. Here’s the listing for NEWSTR:

// newstr.cpp
// using new to get memory for strings
#include <iostream>
#include <cstring>     //for strcpy(), etc
using namespace std;
////////////////////////////////////////////////////////////////
class String //user-defined string type
{
private:
char* str; //pointer to string
public:
String(char* s) //constructor, one arg
{
int length = strlen(s); //length of string argument
str = new char[length+1]; //get memory
strcpy(str, s); //copy argument to it
}
~String() //destructor
{
cout << “Deleting str.\n”;
delete[] str; //release memory
}
void display() //display the String
{
cout << str << endl;
}
};
////////////////////////////////////////////////////////////////
int main()
{ //uses 1-arg constructor
String s1 = “Who knows nothing doubts nothing.”;
cout << “s1=”; //display string
s1.display();
return 0;
}

The output from this program is
s1=Who knows nothing doubts nothing.
Deleting str.

The String class has only one data item: a pointer to char called str. This pointer will point to the string held by the String object. There is no array within the object to hold the string. The string is stored elsewhere; only the pointer to it is a member of String.

Constructor in NEWSTR

The constructor in this example takes a normal char* string as its argument. It obtains space in memory management for this string with new; str points to the newly obtained memory. The constructor then uses strcpy() to copy the string into this new space.

Destructor in NEWSTR

We haven’t seen many destructors in our examples so far, but now that we’re allocating memory with new, destructors become important. If we allocate memory when we create an object, it’s reasonable to deallocate the memory management when the object is no longer needed. As you may recall from before Chapter, a destructor is a routine that is called automatically when an object is destroyed. The destructor in NEWSTR looks like this:

~String()
{
cout << “Deleting str.”;
delete[] str;
}

This destructor gives back to the system the memory management obtained when the object was created. You can tell from the program’s output that the destructor executed at the end of the program. Objects (like other variables) are typically destroyed when the function in which they were defined terminates. This destructor ensures that memory obtained by the String object will be returned to the system, and not left in limbo, when the object is destroyed.

We should note a potential glitch in using destructors as shown in NEWSTR. If you copy one String object to another, say with a statement like s2 = s1, you’re really only copying the pointer to the actual (char*) string. Both objects now point to the same string in memory. But if you now delete one string, the destructor will delete the char* string, leaving the other object with an invalid pointer. This can be subtle, because objects can be deleted in nonobvious ways, such as when a function in which a local object has been created returns. In next chapter we’ll see how to make a smarter destructor that counts how many String objects are pointing to a string.

Read More Topics
Dynamic memory allocation
Inline function in C++
Virtual function in C++
Calloc in C

About the author

Santhakumar Raja

Hi, This blog is dedicated to students to stay update in the education industry. Motivates students to become better readers and writers.

View all posts

Leave a Reply