Questions on delete[] operator when pointer to an array is involved - c++

The following code compiles but runs with mistake:
int main() {
int (*d)[2] = new int[3][2];
// do something
delete [] *d; // this is wrong
delete [] *(d+1); // this is also wrong
//delete [] d; // this works
return 0;
}
I do not know why "delete [] *d" does not work because *d seems to be a pointer to a chunk containing 2 integers and delete[] should destroy that chunk.
Furthermore, I am not sure whether "delete [] d" is enough to release all six elements since two-dimension array is involved here.
Thanks!

The memory you allocated is allocated as one continuous block (or chunk) of memory that stores an array obejct of int[3][2] type. It should be freed as one block
delete [] d;
That's all you need to do.
Freeing just some partial sub-block of a whole block is not supported by C++ dynamic memory management mechanisms.
Your delete [] *d is indeed wrong - the behavior is undefined. However, it has a good chance of "working" in practice since int (*)[2] pointer d and [decayed] int * pointer *d point to the same spot in memory, and the underlying types are trivial. If it "works", it should typically have the same effect as delete [] d;, i.e. free the entire 2D array.

int[3][2] is not a pointer of pointers but just a multi-dimensional array, allocated as a single pointer.
You cannot delete "lines" of it because there are no lines. Memory is contiguous.

Related

Problem in Deleting the elements of an array allocated with new[]

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?
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.
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 [].
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.
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.
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).

Confusion about delete operator in C++

This looks simple question but my friend debated with me that below program invokes UB. But I think he is incorrect.
Consider following program:
#include <iostream>
int main()
{
int* p=new int[3]();
int* q=p;
for(int i=0;i<3;i++)
std::cout<<q[i]<<' ';
delete[] q;
std::cout<<'\n';
}
Is this program's behavior well defined? What happen if I write delete[] p; instead of delete[] q; ? Is it valid?
Yes the program is well defined. First you create a pointer assigned to newly allocated memory.
int* p=new int[3]();
Then you create another pointer pointing to that memory
int* q=p;
You then use that pointer to assign data into that memory. After that you delete memory which is pointer to q which is the same as p which is okay. The program returns and all is well
delete doesn't care about what variable you use. What is important is that the memory that the pointer points to was created with new and that you only call delete once on the memory.
The pointer returned by the new[] operator is not the start of the allocated memory but rather points to the first object (or the object at index 0). Now, based on the compiler you're using, the run-time system stores the number of objects, n, somewhere where it can be retrieved if you only know the memory location pointed by p.
According to this blog, the deletion of a vector performs this operation in reverse:
When you do "delete[] p", you are saying, "p points to a bunch of
objects, but I'm not telling you how many." In this case, the compiler
needs to generate extra code to keep track of how many it needs to
destruct. This extra information is kept in a "secret place" when the
vector is allocated with "new[]".
Since doing int *q = p essentially points to the same array's 0th object, it is equivalent to call delete[] q and delete[] p.
Operator delete can be applied ONLY to memory (i.e. address) that was allocated with operator new. If you allocate once you should free (detele) also once, does not metter which pointer (variable storing address) is used, so your code is valid.
But, remember, after you delete[] q neither q nor p DO NOT have to be used. The best way is assigne NULL to both pointers.
No UB. It will work fine. Not much to add here.

delete[] vs delete in a for loop [duplicate]

This question already has answers here:
delete vs delete[] operators in C++
(7 answers)
Closed 9 years ago.
What is the difference between doing:
int* I = new int[100];
for (int J = 0; J < 100; ++J)
{
delete I++;
}
//and
int* I = new int[100];
delete[] I;
I know that the first is wrong. I know how to use delete[] vs. delete correctly.
I just want to know why these are any different. Like figure out the real difference between delete[] and delete in a loop. So what is the difference?
Both versions of new and delete each have two tasks: allocation/deallocation and construction/destruction.
new will allocate memory and call a constructor.
delete will call a deconstructor and deallocate memory.
new [] allocates single chunk of memory and then calls a constructor possibly several times.
delete [] calls a deconstructor possibly several times and then deallocates a single chunk of memory.
So using delete multiple times means deallocating multiple chunks of memory whereas using delete[] will deallocate a single chunk of memory; using delete multiple times is not equivalent to using delete [].
The difference is that in the first, you're deleting pointers that you didn't get back from new.
There's no point of comparision
Use deletes for all news
and delete []s for all new []s
The first one simply deletes pointer not coming from new
When you use new Foo[n], you're making a single allocation for a chunk of memory big enough to hold an array of n contiguous elements of type Foo. This is not the same as allocating n contiguous chunks of memory, one for each Foo.
From the point of view of the memory allocator, it's really only one big allocation. When you do delete array or delete (array + 42), the memory allocator is basically asked to delete the part of the big allocation that holds a specific item, which it cannot do. It's like trying to free up a single member of a new'ed object by doing delete (&(new Foo())->bar) - what happens to the rest of the object?
Even on a single-element array, delete array will not work because the allocator uses different bookkeeping logic for arrays and single objects (for example, storing the number of elements in the array). So you really do have to use delete[] with new[] and delete with new.
This is declaring an array of integers:
int* I = new int[100];
This is iterating through an array of integers and trying to delete them:
for (int J = 0; J < 100; ++J)
{
delete I++; // bad
}
This is deleting the array of integers:
delete [] I; // correct
Since you allocated the array with [], you deallocate it with []. You do not deallocate memory you allocated with [] without [].
The difference between delete and delete[] is that delete will invoke the destructor of one object, while delete[] will invoke the destructor of every object in the array. In the case of ints, the difference isn't noticable, but if you anything of consequence in your destructor, you'll problems since you won't be properly destroying all of your objects.
That said, you still shouldn't use delete instead of delete[] for simple types since the compiled code may be different for the two operators (for example, delete[] may be expecting an integer to be stored somewhere adjacent to the array to indicate the number of objects to delete). So, the general rule is if you used new, always use delete, and if you used new[], always use delete[].
The first example yields undefined behavior, because a plain delete expression (as opposed to delete[]) can only be applied to an operand that is either:
a null pointer value
a pointer to a non-array object created by a previous new-expression
or a pointer to a subobject
Calling delete on an individual element of an array allocated with new[] does not fall in either of these categories, because the elements of your array are non-array objects that have NOT been created with an individual new expression.
(C++ standard 5.3.5)

Is there a way to expand a dynamic memory array in C++?

Is there a way to expand a dynamic memory array? like this:
int *a = new int[5];
*a = new int[2];
Is this legal?
You cannot expand this type of a dynamic memory array. You can use malloc and realloc though if you need this facility but I would advice against that and suggest including <vector> and using std::vector instead. It has a resize method.
Also, what you described won't compile. The following will:
1: int *a = new int[5];
2: a = new int[2];
The above will allocate two memory blocks, neither of which will be destroyed. Second line will simply assign a new array to the same int *a pointer. When an allocated memory stops being referenced by any pointer, this is called a memory leak. The above code loses any reference to new int[5] and there is no way to free this memory to the operating system.
Although this is not a very practical example, there are multiple ways to resize an array/vector.
As it is usually practical to increase the array size, I will do just this:
{ // C++ vector on the stack (although internally vector uses memory from the heap)
std::vector<int> a(1024);
// do smth
a.resize(4096); // note: this does not always reallocate
// do smth else
}
{ // C++ everything on the heap
std::vector<int> *a = new std::vector<int>(1024);
// do smth
a->resize(4096); // note: this does not always reallocate
// do smth else
delete a;
}
{ // C style
int *a = (int*)malloc(1024*sizeof(int));
// do smth
a = realloc(a, 4096*sizeof(int));
// do smth else
free(a);
}
It is worth to note that realloc does not do anything smart. All it does is:
Allocate new memory block malloc
Copy data from old memory block to new memory block memcpy
Free old memory block free
Return new memory block
You can certainly expand an array, but you need to take care of copying the contents and of freeing the old array (your code, apart from being incorrect syntax, shrinks the array, btw.).
Which is exactly how std::vector works, just you don't have to care.
So basically, having int *a already allocated, what needs to happen is something like:
{
std::unique_ptr<int[]> d(a);
a = new int[desired_new_size];
for(unsigned int i = 0; i < min_old_size_and_new_size; ++i)
a[i] = d[i];
}
Note that strictly speaking "expanding" never really expands the array, but replaces it with another bigger one (that is true for any containers offering the same functionality too). But this is transparent to any code using the pointer later, nobody will know.
You should never use realloc (or any other C memory allocation functions) in combination with memory allocated or freed by operator new and delete (or new[] and delete[]) as pointed out above.
This may work (and usually will), but it's conceptually wrong, and it's pure luck (unknown implementation detail) if it does not crash.

How does delete[] know it's an array?

Alright, I think we all agree that what happens with the following code is undefined, depending on what is passed,
void deleteForMe(int* pointer)
{
delete[] pointer;
}
The pointer could be all sorts of different things, and so performing an unconditional delete[] on it is undefined. However, let's assume that we are indeed passing an array pointer,
int main()
{
int* arr = new int[5];
deleteForMe(arr);
return 0;
}
My question is, in this case where the pointer is an array, who is it that knows this? I mean, from the language/compiler's point of view, it has no idea whether or not arr is an array pointer versus a pointer to a single int. Heck, it doesn't even know whether arr was dynamically created. Yet, if I do the following instead,
int main()
{
int* num = new int(1);
deleteForMe(num);
return 0;
}
The OS is smart enough to only delete one int and not go on some type of 'killing spree' by deleting the rest of the memory beyond that point (contrast that with strlen and a non-\0-terminated string -- it will keep going until it hits 0).
So whose job is it to remember these things? Does the OS keep some type of record in the background? (I mean, I realise that I started this post by saying that what happens is undefined, but the fact is, the 'killing spree' scenario doesn't happen, so therefore in the practical world someone is remembering.)
One question that the answers given so far don't seem to address: if the runtime libraries (not the OS, really) can keep track of the number of things in the array, then why do we need the delete[] syntax at all? Why can't a single delete form be used to handle all deletes?
The answer to this goes back to C++'s roots as a C-compatible language (which it no longer really strives to be.) Stroustrup's philosophy was that the programmer should not have to pay for any features that they aren't using. If they're not using arrays, then they should not have to carry the cost of object arrays for every allocated chunk of memory.
That is, if your code simply does
Foo* foo = new Foo;
then the memory space that's allocated for foo shouldn't include any extra overhead that would be needed to support arrays of Foo.
Since only array allocations are set up to carry the extra array size information, you then need to tell the runtime libraries to look for that information when you delete the objects. That's why we need to use
delete[] bar;
instead of just
delete bar;
if bar is a pointer to an array.
For most of us (myself included), that fussiness about a few extra bytes of memory seems quaint these days. But there are still some situations where saving a few bytes (from what could be a very high number of memory blocks) can be important.
The compiler doesn't know it's an array, it's trusting the programmer. Deleting a pointer to a single int with delete [] would result in undefined behavior. Your second main() example is unsafe, even if it doesn't immediately crash.
The compiler does have to keep track of how many objects need to be deleted somehow. It may do this by over-allocating enough to store the array size. For more details, see the C++ Super FAQ.
Yes, the OS keeps some things in the 'background.' For example, if you run
int* num = new int[5];
the OS can allocate 4 extra bytes, store the size of the allocation in the first 4 bytes of the allocated memory and return an offset pointer (ie, it allocates memory spaces 1000 to 1024 but the pointer returned points to 1004, with locations 1000-1003 storing the size of the allocation). Then, when delete is called, it can look at 4 bytes before the pointer passed to it to find the size of the allocation.
I am sure that there are other ways of tracking the size of an allocation, but that's one option.
This is very similar to this question and it has many of the details your are looking for.
But suffice to say, it is not the job of the OS to track any of this. It's actually the runtime libraries or the underlying memory manager that will track the size of the array. This is usually done by allocating extra memory up front and storing the size of the array in that location (most use a head node).
This is viewable on some implementations by executing the following code
int* pArray = new int[5];
int size = *(pArray-1);
delete or delete[] would probably both free the memory allocated (memory pointed), but the big difference is that delete on an array won't call the destructor of each element of the array.
Anyway, mixing new/new[] and delete/delete[] is probably UB.
It doesn't know it's an array, that's why you have to supply delete[] instead of regular old delete.
I had a similar question to this. In C, you allocate memory with malloc() (or another similar function), and delete it with free(). There is only one malloc(), which simply allocates a certain number of bytes. There is only one free(), which simply takes a pointer as it's parameter.
So why is it that in C you can just hand over the pointer to free, but in C++ you must tell it whether it's an array or a single variable?
The answer, I've learned, has to do with class destructors.
If you allocate an instance of a class MyClass...
classes = new MyClass[3];
And delete it with delete, you may only get the destructor for the first instance of MyClass called. If you use delete[], you can be assured that the destructor will be called for all instances in the array.
THIS is the important difference. If you're simply working with standard types (e.g. int) you won't really see this issue. Plus, you should remember that behavior for using delete on new[] and delete[] on new is undefined--it may not work the same way on every compiler/system.
It's up to the runtime which is responsible for the memory allocation, in the same way that you can delete an array created with malloc in standard C using free. I think each compiler implements it differently. One common way is to allocate an extra cell for the array size.
However, the runtime is not smart enough to detect whether or not it is an array or a pointer, you have to inform it, and if you are mistaken, you either don't delete correctly (E.g., ptr instead of array), or you end up taking an unrelated value for the size and cause significant damage.
ONE OF THE approaches for compilers is to allocate a little more memory and store count of elements in the head element.
Example how it could be done:
Here
int* i = new int[4];
compiler will allocate sizeof(int)*5 bytes.
int *temp = malloc(sizeof(int)*5)
Will store 4 in first sizeof(int) bytes
*temp = 4;
and set i
i = temp + 1;
So i points to array of 4 elements, not 5.
And
delete[] i;
will be processed following way
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements if needed
... that are stored in temp + 1, temp + 2, ... temp + 4
free (temp)
Semantically, both versions of delete operator in C++ can "eat" any pointer; however, if a pointer to a single object is given to delete[], then UB will result, meaning anything may happen, including a system crash or nothing at all.
C++ requires the programmer to choose the proper version of the delete operator depending on the subject of deallocation: array or single object.
If the compiler could automatically determine whether a pointer passed to the delete operator was a pointer array, then there would be only one delete operator in C++, which would suffice for both cases.
Agree that the compiler doesn't know if it is an array or not. It is up to the programmer.
The compiler sometimes keep track of how many objects need to be deleted by over-allocating enough to store the array size, but not always necessary.
For a complete specification when extra storage is allocated, please refer to C++ ABI (how compilers are implemented): Itanium C++ ABI: Array Operator new Cookies
"undefined behaviour" simply means the language spec makes no gaurantees as to what will happen. It doesn't nessacerally mean that something bad will happen.
So whose job is it to remember these things? Does the OS keep some type of record in the background? (I mean, I realise that I started this post by saying that what happens is undefined, but the fact is, the 'killing spree' scenario doesn't happen, so therefore in the practical world someone is remembering.)
There are typically two layers here. The underlying memory manager and the C++ implementation.
Most memory managers were designed to meet the needs of the C language. In C the "free" function does not require the user to specify the size of the block. Therefore the memory manager will remember (among other things) the size of the block of memory that was allocated. This may be larger than the block the C++ implementation asked for. Typically the memory manager will store it's metadata before the allocated block of memory.
C++ has a culture of "you only pay for what you use". Therefore the C++ implementation will generally only remember the size of the array if it needs to do so for it's own purposes, typically because the type has a non-trival destructor.
So for types with a trivial destructor the implementation of "delete" and "delete []" is typically the same. The C++ implementation simply passes the pointer to the underlying memory manager. Something like
free(p)
On the other hand for types with a non-trivial destructor "delete" and "delete []" are likely to be different. "delete" would be somthing like (where T is the type that the pointer points to)
p->~T();
free(p);
While "delete []" would be something like.
size_t * pcount = ((size_t *)p)-1;
size_t count = *count;
for (size_t i=0;i<count;i++) {
p[i].~T();
}
char * pmemblock = ((char *)p) - max(sizeof(size_t),alignof(T));
free(pmemblock);
You cannot use delete for an array, and you cannot use delete [] for a non-array.
Hey ho well it depends of what you allocating with new[] expression when you allocate array of build in types or class / structure and you don't provide your constructor and destructor the operator will treat it as a size "sizeof(object)*numObjects" rather than object array therefore in this case number of allocated objects will not be stored anywhere, however if you allocate object array and you provide constructor and destructor in your object than behavior change, new expression will allocate 4 bytes more and store number of objects in first 4 bytes so the destructor for each one of them can be called and therefore new[] expression will return pointer shifted by 4 bytes forward, than when the memory is returned the delete[] expression will call a function template first, iterate through array of objects and call destructor for each one of them. I've created this simple code witch overloads new[] and delete[] expressions and provides a template function to deallocate memory and call destructor for each object if needed:
// overloaded new expression
void* operator new[]( size_t size )
{
// allocate 4 bytes more see comment below
int* ptr = (int*)malloc( size + 4 );
// set value stored at address to 0
// and shift pointer by 4 bytes to avoid situation that
// might arise where two memory blocks
// are adjacent and non-zero
*ptr = 0;
++ptr;
return ptr;
}
//////////////////////////////////////////
// overloaded delete expression
void static operator delete[]( void* ptr )
{
// decrement value of pointer to get the
// "Real Pointer Value"
int* realPtr = (int*)ptr;
--realPtr;
free( realPtr );
}
//////////////////////////////////////////
// Template used to call destructor if needed
// and call appropriate delete
template<class T>
void Deallocate( T* ptr )
{
int* instanceCount = (int*)ptr;
--instanceCount;
if(*instanceCount > 0) // if larger than 0 array is being deleted
{
// call destructor for each object
for(int i = 0; i < *instanceCount; i++)
{
ptr[i].~T();
}
// call delete passing instance count witch points
// to begin of array memory
::operator delete[]( instanceCount );
}
else
{
// single instance deleted call destructor
// and delete passing ptr
ptr->~T();
::operator delete[]( ptr );
}
}
// Replace calls to new and delete
#define MyNew ::new
#define MyDelete(ptr) Deallocate(ptr)
// structure with constructor/ destructor
struct StructureOne
{
StructureOne():
someInt(0)
{}
~StructureOne()
{
someInt = 0;
}
int someInt;
};
//////////////////////////////
// structure without constructor/ destructor
struct StructureTwo
{
int someInt;
};
//////////////////////////////
void main(void)
{
const unsigned int numElements = 30;
StructureOne* structOne = nullptr;
StructureTwo* structTwo = nullptr;
int* basicType = nullptr;
size_t ArraySize = 0;
/**********************************************************************/
// basic type array
// place break point here and in new expression
// check size and compare it with size passed
// in to new expression size will be the same
ArraySize = sizeof( int ) * numElements;
// this will be treated as size rather than object array as there is no
// constructor and destructor. value assigned to basicType pointer
// will be the same as value of "++ptr" in new expression
basicType = MyNew int[numElements];
// Place break point in template function to see the behavior
// destructors will not be called and it will be treated as
// single instance of size equal to "sizeof( int ) * numElements"
MyDelete( basicType );
/**********************************************************************/
// structure without constructor and destructor array
// behavior will be the same as with basic type
// place break point here and in new expression
// check size and compare it with size passed
// in to new expression size will be the same
ArraySize = sizeof( StructureTwo ) * numElements;
// this will be treated as size rather than object array as there is no
// constructor and destructor value assigned to structTwo pointer
// will be the same as value of "++ptr" in new expression
structTwo = MyNew StructureTwo[numElements];
// Place break point in template function to see the behavior
// destructors will not be called and it will be treated as
// single instance of size equal to "sizeof( StructureTwo ) * numElements"
MyDelete( structTwo );
/**********************************************************************/
// structure with constructor and destructor array
// place break point check size and compare it with size passed in
// new expression size in expression will be larger by 4 bytes
ArraySize = sizeof( StructureOne ) * numElements;
// value assigned to "structOne pointer" will be different
// of "++ptr" in new expression "shifted by another 4 bytes"
structOne = MyNew StructureOne[numElements];
// Place break point in template function to see the behavior
// destructors will be called for each array object
MyDelete( structOne );
}
///////////////////////////////////////////
just define a destructor inside a class and execute your code with both syntax
delete pointer
delete [] pointer
according to the output u can find the solutions
The answer:
int* pArray = new int[5];
int size = *(pArray-1);
Posted above is not correct and produces invalid value.
The "-1"counts elements
On 64 bit Windows OS the correct buffer size resides in Ptr - 4 bytes address