Reputation: 1851
This question was asked as part of Does delete[] deallocate memory in one shot after invoking destructors? but moved out as a separate question.
It seems (Correct me if wrong) that the only difference between delete
and delete[]
is that delete[]
will get the array size information and invoke destructors on all of them, while delete
will destruct the only first one. In particular, delete
also has access to the info on how much total memory is allocated by new[]
.
If one doesn't care about destructing the dynamically allocated array elements, and only care that the memory allocated either by new
or new[]
be deallocated, delete
seems to be able to do the same job.
This How does delete[] "know" the size of the operand array? question's accepted answer has one comment from @AnT and I quote
Also note that the array element counter is only needed for types with non-trivial destructor. For types with trivial destructor the counter is not stored by new[] and, of course, not retrieved by delete[]
This comment suggests that in general delete
expression knows the amount of the entire memory allocated and therefore knows how much memory to deallocate in one shot in the end, even if the memory hold an array of elements. So if one writes
auto pi = new int[10];
...
delete pi;
Even though the standard deems this as UB, on most implementations, this should not leak memory (albeit it is not portable), right?
Upvotes: 2
Views: 231
Reputation: 140688
A concrete reason to avoid all constructs provoking undefined behavior, even if you cannot see how they could possibly go wrong, is that the compiler is entitled to assume that undefined behavior never happens. For instance, given this program...
#include <iostream>
#include <cstring>
int main(int argc, char **argv)
{
if (argc > 0) {
size_t *x = new size_t[argc];
for (int i = 0; i < argc; i++)
x[i] = std::strlen(argv[i]);
std::cout << x[0] << '\n';
delete x;
}
return 0;
}
... the compiler might emit the same machine code as it would for ...
int main(void) { return 0; }
... because the undefined behavior on the argc > 0
control path means the compiler may assume that path is never taken.
Upvotes: 0
Reputation: 275600
Under the C++ standard, calling delete
on something allocated with new[]
is simply undefined behavior, as is calling delete[]
on something allocated with new
.
In practice, new[]
will allocate the memory through something like malloc
as will new
. delete
will destroy the pointed-to object, then send the memory to something like free
. delete[]
will destroy all of the objects in the array, then send the memory to something like free
. Some extra memory may be allocated by new[]
to pass to delete[]
to give delete[]
the number of elements to be destroyed, or not.
If actual malloc
/free
is used, then some implementations will allow a pointer to anywhere in the malloc'd block to be used. Others won't. The exact same value is required to be passed to free
as you got from malloc
for this to be defined. There is an issue here in that if new[]
malloced some extra room for the array size/element stride and stuck it before the block, then delete
is passed the pointer-to-the-first element, then delete
will pass free
a different pointer than new[]
got from malloc
. (I think there is an architecture where something like this happens.)
Like most undefined behavior, you can no longer rely on auditing the code you write, but instead you are now committed to auditing both the produced assembly, and the C/C++ standard libraries you interact with, before you can determine if the behavior you want to do is correct. In practice, that is a burden that will not be fulfilled, so your code ends up having negative value, even if you check that things work the way you expect the one time you actually checked. How will you ensure that an identical check (of the resulting binary and its behavior) will occur every time the compiler version, standard library version, OS version, system libraries, or compiler is changed?
Upvotes: 3
Reputation: 62583
This is correct. Difference between delete and delete[] is that the latter knows the number of items allocated in the array and calls destructor on every object on them. To be 100% correct, both actually 'know' it - the number of items allocated for an array is equal to the allocated memory size (which both know) divided by the size of the object.
One might ask, why do we need delete[] and delete than - why can't delete perform the same calculations? The answer is polymorphism. The size of the allocated memory will not be equal to the sizeof static objec when deletion is done through the pointer to the base class.
On the other hand, delete[] does not take into account a possibility of object being polymorphed, and this is why dynamic arrays should never be treated as polymorphic objects (i.e. allocated and stored as a pointer to the base class).
As for leaking memory, delete will not leak memory in case of POD types when used on arrays.
Upvotes: 0