Dynamic Memory in C++ (new and delete)

We looked at dynamic memory in C last week, so let’s compare it with dynamic memory in C++.

Allocation

In C++, if you want to allocate on the heap rather than the stack, you need to use the new operator.

Just like the C equivalents, the new operator returns a void* pointer to the block of memory that has been allocated.

There are two versions of new, the first returns a single item:

int* x;
x = new int;

The second, using square brackets, returns an array of items:

int* x;
x = new int[16];

Checking for success

C allocators return NULL and set errno when they fail, which you should explicitly check for.

In C++ however, an exception is thrown (bad_alloc). If you don’t have the code in place to catch the exception, your program will terminate.

You can force C++ to behave like C by passing the nothrow argument to new:

int* x;
x = new(nothrow) int;

Now new will behave like a C function and set x to NULL if it fails.

Of course, if you do this, you’ll remember check for a NULL value before using the pointer, won’t you?

Clearing up

Just like in C, you MUST remember to clear up after yourself when you’ve spent the afternoon happily declaring memory on the heap.

To do this, you need to call delete. There are two versions of delete that match the two versions of new:

//for single objects
delete x;
//for arrays
delete[] x;

What if you use the wrong one?

If you forget to use the brackets on an allocated array, you will only delete the first element. The others will remain inaccessible in memory, causing a memory leak. And you don’t want that to happen, do you?

If you use the bracketed version on a single object the behaviour is undefined. Which, if you’re unsure, means you can’t rely on the result to be anything you might expect 🙂

Can you mix and match between new, malloc, delete and free?

No. Never do this!

First off, it’s just plain wrong to mix functionality from two separate languages (even though you can).

Second, new and delete are used in C++ because they call the constructor and destructor of an object respectively. The C equivalents, malloc and free do not do this.

So, if you create an object with malloc, any work done in the constructor will not happen.

Worse, if you free an object that was allocated with new (instead of using delete), the object’s destructor is not called. If your object uses memory dynamically and the destructor does the clearing up, then what will you have? Yes, a memory leak.

But that won’t happen to you now, because you’ve just read this, right? 😉

Dynamic Memory in C (malloc, calloc, realloc, free)

Let’s take a look at the four methods that allow us to utilize dynamic memory in C. Dynamic memory just means we are using memory on the heap, instead of on the stack.

Why would you want to use dynamic memory?

You might want to create a variable or object that persists beyond the scope of the function it is created in (i.e. to share it between functions). The only way to do this is to create it dynamically, and then remember to deallocate it at a later point. Alternatively, you might not know the size of something you are using until runtime (e.g. reading in a file), in which case the heap is a better place to store your data. Why? Because the size of the stack is limited and it may be too small for unknown data processed at runtime.

How do you dynamically allocate in C?

There are three functions for memory allocation (plus one for deallocation). Each allocator returns a void* to the memory that has been allocated, which can be cast to the appropriate type.

Let’s look at each in turn:

1. malloc

This is the most commonly used method. Simply pass in how big you want your memory to be (in bytes), and you get a pointer to that memory back. The memory is uninitialized. If it fails it returns NULL.

2. calloc

Instead of passing in a size, you tell calloc how many of a certain type of variable you are going to use. E.g. 10 ints, or 16 structs. The memory is initialized to zeros. If it fails it returns NULL.

3. realloc

This method resizes an existing block of memory and you can make your existing memory allocation bigger or smaller. It frees the existing block and returns a void* to the new block. If you pass in zero, it effectively frees the memory in question. If it fails it returns NULL (see the comments in the code below for why you should pay careful attention to how you use realloc).

And what do you do when you’re finished?

You call free, nice and easy, and your memory is released (although it is not “deleted” as such – the data may exist until something else overwrites it, or part of it, or until the program ends).

Note that calls to malloc, calloc and realloc set errno if they fail. You can find out how to use errno here!

Can I see an example?

Sure – here’s a little bit of code that uses all four methods so you can see them at work:

#include <stdlib.h>

#define BIG_NUMBER 1024
#define SMALL_NUMBER 16

struct msg
{
	int code;
	char message[BIG_NUMBER];
};

int main(void)
{
	char* buffer;
	struct msg* messagelist;

	/* Allocate some memory from the heap */
	buffer = (char*)malloc(BIG_NUMBER);
	if (buffer != NULL)
	{
		/* I can use the memory safely */
	}

	/* Reduce the size of the memory */
	char* smallbuffer = (char*)realloc(buffer, SMALL_NUMBER);
	if (smallbuffer != NULL)
	{
		/* I can use the memory safely */
	}

	/*******************************************
	 * NOTE: Look carefully at the realloc call above.
	 * If the call to realloc had failed and I had assigned
	 * it to the original buffer like so:
	 *     buffer = (char*)realloc(buffer, SMALL_NUMBER);
	 * then my buffer would have been set to NULL and I would
	 * not only lose access to the data that was stored
	 * there, but I'd create a memory leak too!
	 *******************************************/

	/* Allocate some memory from the heap */
	messagelist = (struct msg*)calloc(SMALL_NUMBER, sizeof(struct msg));
	if (messagelist != NULL)
	{
		/* I can use the memory safely */
	}

	/* Remember to clear up after myself */
	free(smallbuffer);
	free(messagelist);

	/* NOTE: I DON'T need to free the 'buffer' variable */
	/* because realloc already did it for me 🙂 */

	return EXIT_SUCCESS;
}