Home > front end >  Problem in Deleting the elements of an array allocated with new[]
Problem in Deleting the elements of an array allocated with new[]

Time:09-08

This question is similar to Problem with delete[], how to partially delete the memory?

I understand that deleting an array after incrementing its pointer is not possible as it loses the track of how many bytes to clean. But, I am not able to understand why one-by-one delete/deallocation of a dynamic array doesn't work either.

int main()
{
    int n = 5;
    int *p = new int[n];
 
    for(int i=0;i<n;  i){
        delete &p[i];
    }
}

I believe this should work, but in clang 12.0 it fails with the invalid pointer error. Can anyone explain why?

CodePudding user response:

An array is a contiguous object in memory of a specific size. It is one object where you can place your data in and therefore you can only free/delete it as one object.

You are thinking that an array is a list of multiple objects, but that's not true. That would be true for something like a linked list, where you allocate individual objects and link them together.

CodePudding user response:

You allocated one object of the type int[n] (one extent of memory for an array) using the operator new

int *p = new int[n];

Elements of the array were not allocated dynamically separately.

So to delete it you just need to write

delete []p;

If for example you allocated an array of pointers like

int **p = new int *[n];

and then for each pointer of the array you allocated an object of the type int like

for ( int i = 0;i < n;  i ) 
{
    p[i] = new int( i );
}

then to delete all the allocated objects you need to write

for ( int i = 0; i < n;   i )
{
    delete p[i];
}
delete []p;

That is the number of calling of the operator delete or delete [] one to one corresponds to the number of calling operator new or new [].

CodePudding user response:

One new always goes with one delete. Just as that.

In detail, when we request an array using new, what we actually do is to get a pointer that controls a contiguous & fixed block on the memory. Whatever we do with that array, we do it through that pointer and this pointer associates strictly with the array itself.

Furthermore, let's assume that you were able to delete an elemnent in the middle of that array. After the deletion, that array would fall apart and they are not contiguous anymore! By then, an array would not really be an array!

Because of that, we can not 'chop off' an array into separate pieces. We must always treat an array as one thing, not distinctive elements scattered around the memory.

CodePudding user response:

Greatly simplyfyinh: in most systems memory is allocated in logical blocks which are described by the starting pointer of the allocated block.

So if you allocate an array:

int* array = new int[100];

OS stores the information of that allocation as a pair (simplifying) (block_begin, size) -> (value of array ptr, 100)

Thus when you deallocate the memory you don't need to specify how much memory you allocated i.e:

// you use
delete[] array; // won't go into detail why you do delete[] instead of delete - mostly it is due to C   way of handling destruction of objects
// instead of
delete[100] array;

In fact in bare C you would do this with:

int* array = malloc(100 * sizeof(int))
[...]
free(array)

So in most OS'es it is not possible due to the way they are implemented.

However theoretically allocating large chunk of memory in fact allocate many smaller blocks which could be deallocated this way, but still it would deallocate smaller blocks at a time not one-by-one.

CodePudding user response:

All of new or new[] and even C's malloc do exactly the same in respect to memory: requesting a fix block of memory from the operating system.

You cannot split up this block of memory and return it partially to the operating system, that's simply not supported, thus you cannot delete a single element from the array either. Only all or none…

If you need to remove an element from an array all you can do is copy the subsequent elements one position towards front, overwriting the element to delete and additionally remember how many elements actually are valid – the elements at the end of the array stay alive!

If these need to be destructed immediately you might call the destructor explicitly – and then assure that it isn't called again on an already destructed element when delete[]ing the array (otherwise undefined behaviour!) – ending in not calling new[] and delete[] at all but instead malloc, placement new for each element, std::launder any pointer to any element created that way and finally explicitly calling the constructor when needed.

Sounds like much of a hassle, doesn't it? Well, there's std::vector doing all this stuff for you! You should this one it instead…

Side note: You could get similar behaviour if you use an array of pointers; you then can – and need to – maintain (i.e. control its lifetime) each object individually. Further disadvantages are an additional level of pointer indirection whenever you access the array members and the array members indeed being scattered around the memory (though this can turn into an advantage if you need to move objects around your array and copying/moving objects is expensive – still you would to prefer a std::vector, of pointers this time, though; insertions, deletions and managing the pointer array itself, among others, get much safer and much less complicated).

  • Related