Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Understanding Operator new[] and Operator delete[]

3.21/5 (42 votes)
21 Sep 2006CPOL3 min read 1   182  
Understand what methods are used for managing memory for array

Introduction

Memory management is very critical and hence an interesting topic in C/C++. In C, malloc and free are present. In C++, operator new and operator delete are provided, which give better control.

Operator new and operator delete internally call the same old malloc/free . But they are called by new operator and delete operator, which calls object constructor and destructor for initialization and clean up.

Intermixing new/delete and malloc/free should be avoided. In such cases, results are undefined and messy.

operator new

This operator internally calls malloc, and initializes object from memory. A simple form of this operator is:

C++
static void* operator new(size_t size)
{
    FreeStore* p=(FreeStore*)malloc(sizeof(FreeStore));
    return p;
}

operator delete

This operator internally calls free:

C++
static void operator delete(void *p)
{
     free(p);
}

Placement new

The special operator new does nothing and is used to construct object from raw memory. It is simply implemented as:

C++
void *operator new (size_t, void *p)
 {
    return p;
 }

First is irrelevant, but mandatory. And this operator returns a memory address passed to it. Later it is used for object construction. You can see this definition in <new.h>.

Placement delete

In a class for every form of new, there should be a corresponding delete present. If you define operator placement new in your class and forget to define the corresponding placement delete, the compiler will remind you. A simple form of placement delete is:

C++
static void operator delete(void*,void *)
{
 return;
}

operator new[] and operator delete[]

When allocating memory for an array of objects, things become interesting. Consider the following code snippet:

C++
FreeStore* pArrayOfObject=new FreeStore[1];
delete [] pArrayOfObject;

In the above code, operator new[] and operator delete[] are used. Now we'll discuss methods used for implementing these operators. How is the track of array size kept.

Methods Used

There are two commonly used methods to achieve this:

  1. Keep information about size of array, for that allocates extra memory.
  2. Keep a global map, where pointer is stored as key, and its array size as value.

Here is a brief explanation of how it can be achieved.

1. Book Keeping

As said earlier, allocate enough memory to hold extra information, i.e. of size of array. While deleting that array, unwrap that memory and use for deletion. In my example, I used 4 bytes for storing extra information. It is declared as:

C++
const size_t BOOKKEEPING_SIZE=4;

Class FreeStore_BookKeep is used to demonstrate this.

I've used static method operator_new which would be called to allocate array of elements, it takes argument size_t, i.e., number of elements to be allocated.

memory allocation

This method would be like this.

C++
// here actual allocated size is, BOOKKEEPING_SIZE more than requested
size_t* ptmpObject = (size_t*) malloc(BOOKKEEPING_SIZE + nsize * 
					sizeof(FreeStore_BookKeep));
//keep size in to preceding buffer
*ptmpObject=size;
FreeStore_BookKeep* pThis = (FreeStore_BookKeep*) ( ptmpObject + BOOKKEEPING_SIZE) ;
size_t i(0);
//in case constructor throws exception, free allocated memory
for (i ; i < size; ++i)
{
    //initialize FreeStore_BookKeep object from raw memory
    new (pThis+i) FreeStore_BookKeep();
}
//returned memory is not  ptmpObject, which is originally allocated.
return pThis;

In the above method, memory allocated is more than what is requested. For deleting this array, static method operator_delete is used, while takes void* as parameter. i.e. pointer to delete memory. This method uses same information kept in extra bytes, to free the memory. Its implementation is like this,

C++
//to access size, need to look preceding memory area
size_t *ptemp=(size_t*)pMemoryToDelete-BOOKKEEPING_SIZE;
size_t size=(size_t)(*ptemp);
//need to call d'tor now
FreeStore_BookKeep *pThis=(FreeStore_BookKeep*)(pMemoryToDelete);
for (size_t i=0; i<size;i++)
{
    (pThis+i)->~FreeStore_BookKeep();
}
//Here free all memory allocated, considering book keeping
free(ptemp);

The main drawback of this method is, if user doesn't use delete[](operator_delete in this case), and uses normal delete on pointer, then number of BOOKKEEPING_SIZE bytes will never be freed.

2. Using Global Map

Use global map to store information about pointer and number of elements, i.e. while allocating memory, store pointer allocated as key, and number of elements as value, in global map. And while deleting memory, access the same map to find the number of elements allocated.

Class FreeStore_Map is used to demonstrate this. Global map is declared as:

C++
typedef map<void*,size_t> MemoryInfo;
MemoryInfo gKeepSizeTrack;

New operator_new method will look like this:

C++
FreeStore_Map *pThis = (FreeStore_Map*) malloc(nsize * sizeof(FreeStore_Map));
size_t i(0);
for (i ; i < nsize; ++i)
{
     //placement new just returns pointer passed ,
     //initializes objects from raw memory
     new (pThis+i) FreeStore_Map();
}
//save pointer in global map
gKeepSizeTrack[pThis]=nsize;
return pThis;

Now, while deleting memory, the same map is accessed. New operator_delete will look like this:

C++
//look for global map
MemoryInfo::iterator it=gKeepSizeTrack.find(p);
//get size
size_t nsize=it->second;
FreeStore_Map* pTemp=(FreeStore_Map*)p;
for (size_t i=0; i<nsize;i++)
{
    (pTemp+i)->~FreeStore_Map();
}
//remove from global map
gKeepSizeTrack.erase(p);
//free memory allocated
free(p);

operator_new and operator_delete need to be static in nature. Because operator new is the method that initializes/constructs class calling constructor and operator delete destroys object, these methods need to be static in nature.

Using this Code

The main function of code supplied looks like this:

C++
//array of 100 elements using Book keep method
FreeStore_BookKeep *pObjArr=FreeStore_BookKeep::operator_new(100);
FreeStore_BookKeep::operator_delete(pObjArr);//delete it
//array of 200 elements using global map method
FreeStore_Map *pObjArr1=FreeStore_Map::operator_new(200);
FreeStore_Map::operator_delete(pObjArr1);//delete it

References

  • MSDN article "Handling Exceptions, Part 5", By Robert Schmidt

History

  • Sept 14, 2006: Published
  • Sept 17, 2006: Updated
  • Sept 21, 2006: Updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)