delete [] my_data_element;
By the name 'my_data_element' the compiler can know that this is an
array and it also knows the size from the definition, why does the
language require '[]' to be specified with 'delete'?
Are there cases where the compiler wouldn't know about this (the
number of elements in the array)?
-Krishna.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Yes, in all cases the compiler does not know, and in many cases cannot
know. Consider:
char * p = new char[4];
The char * is just a char *, it doesn't have any way of storing the
additional information that it actually points at an array. This is even
clearer in cases like this:
char * alloc( int n ) {
if ( n == 1 ) {
return new char;
else {
return new char[n];
}
}
char * p = alloc(4);
For the compiler to track this kind of thing, it would have to perform
an enormous amount of book-keeping, and that book-keeping information
would have to be encoded somehow in the executable for use at run-time.
The use of the delete[] syntax makes things a lot simpler.
And look on the bright side! C++ used to require you to supply the
correct size of the allocation, so you had to say things like:
char * p = new char[4];
...
delete [4] p;
So things have improved!
Neil Butterworth
template<typename T>
void dispose_array(T* p) {
delete[] p;
}
int main() {
dispose_array(new int[10]);
}
How should the compiler inside dispose_array statically know
whether the pointer p has been allocated by the array form of
new or that p actually points to an array? Consider the following
misuse examples
dispose_array(new int);
int i;
dispose_array(&i);
Obviously this still compiles, but causes UB if evaluated. The
reason being that both the delete and the delete[] expression
operator need to accept a pointer to object type.
HTH & Greetings from Bremen,
Daniel Kr�gler
Yes, any time the pointer holding its location has been passed outside
the function in which the dynamic array was created. In addition there
are the times when ownership of the array is passed on:
type * maketype(unsigned int number);
How does the compiler know from the function declaration that the
returned value will be a pointer to an array?
The key factor is that the destruction of an array needs different
handling to the destruction of a solo object.
void foo(int* p);
int* my_data_element1 = new int; // allocates sizeof(int) bytes
int* my_data_element2 = new int[42]; // allocates 42*sizeof(int) + n
bytes where n is used to store the length and is stored immediately
infront of the array
foo(my_data_element1);
foo(my_data_element2);
// In another file
void foo(int* p)
{
delete p; // Disaster if p is actually pointing to an array
delete [] p; // disaster if p is NOT pointing to an array
}
> Are there cases where the compiler wouldn't know about this (the
> number of elements in the array)?
The compiler clearly doesn't know (see foo above).
The runtime knows (that's why you don't neeed to write delete [42] p)
but it doesn't know whether you are pointing to an array
or a single object and only the array has the length prepended to it
for space saving reasons.
Let us say we have a function:
func(Object *o) {
// do stuff
delete o; /* or should it be []o */
}
This function can be called both as:
func(new Object());
or as:
func(new Object[100]);
A simple example worked for me (the following hasn't been compiled,
but the basic idea should be clear):
class A{
A() {}
~A() { cout << "in dtor" << endl; }
};
int main() {
A* array = new A[10];
delete array; // calls dtor for item A at array[0];
delete [] array; // calls dtor for all items in array
}
Technically, the second delete[] would cause a core dump (or whatever)
since the desctructor is called for array[0] two times.
So that it knows to call the destructor on each element of the array.
> Are there cases where the compiler wouldn't know about this (the
> number of elements in the array)?
The compiler doesn't know it, it is most likely stored just before the
pointer.
[] is essential so that compiler knows that there are multiple
elements in a vector your pointer points to, so that it can call
destructor for each element. If you don't use [], it calls the
destructor for the first element only.
You can use [] even if you only allocate one element. But, if you, for
whatever reason, overload operator new to, for example, allocate more
memory than sizeof(*this), then it is an error to use delete[]. This
is only reason I can think of why we need two flavors for "delete".
Goran.
That is not correct.
> Are there cases where the compiler wouldn't know about this (the
> number of elements in the array)?
Yes. See other posts. Luckily it really doesn't matter as no sane
programmer uses new [] anymore. Array new/delete is from a time before
templates - an anachronism; today you would use std::vector.
/Peter
No, the compiler does not know and cannot that this is an array.
Argument of 'delete[]' is a pointer. 'my_data_element' in the above is a
plain and ordinary _pointer_. The compiler has absolutely no way to know
whether this pointer points to a single object or to a beginning of an
array.
> and it also knows the size from the definition,
No, it doesn't. 'my_data_element' is a pointer and its definition does
not include any "size".
> why does the
> language require '[]' to be specified with 'delete'?
Because of the above.
> Are there cases where the compiler wouldn't know about this (the
> number of elements in the array)?
In _all_ cases the compiler does not know the size.
Moreover, it would be interesting to see an example of what _you_ are
talking about. Can you show us an example of 'delete' applied to an
array where the compiler would knows the size in advance?
--
Best regards,
Andrey Tarasevich
You are mistaken and that last sentence does not matter. Compiler
knows sizeof(TYPE) and the size of the allocated heap block.
So, in
TYPE* p = new TYPE[count];
compiler knows that it should allocate space of count*sizeof(TYPE)
octets.
Similar to that, in
delete [] p;
compiler knows that it should call ~TYPE() on "count" instances of
TYPE, and does that.
Note also: if what you are saying were true, we would have to do e.g.
delete [count, sizeof(TYPE)] p;
Goran.
--
Are you just trying to be awkward?
When the runtime executes a delete x_ptr it calls the dtor for the x
type and then passes the residual base memory to the heap manager (which
knows how much memory it handed out starting at the address held in the
pointer.
When the runtime executes a delete[] x_ptr it first accesses the hidden
location (often the first few bytes of the originally allocated memory)
to determine the number of items in the array. It then iterates over
memory destroying the objects before computing the original address of
the allocated memory so that it can pass that address to the heap manager.
Note that delete and delete[] behave significantly differently though
both operate on a pointer of the same type. That is the crux of the
issue, the compiler needs to know what kind of destruction and recovery
code it has to provide because in general all it can see is a pointer.
Note that because of issues of exception safety no competent programmer
writes delete or delete[] at high level. Handling of dynamic memory is
encapsulated into special classes (smart pointers, collection classes
etc.) that manage dynamic memory transparently and relatively safely.
>
> You can use [] even if you only allocate one element. But, if you, for
> whatever reason, overload operator new to, for example, allocate more
> memory than sizeof(*this), then it is an error to use delete[]. This
> is only reason I can think of why we need two flavors for "delete".
Only if, by one element, you mean new T[1]
If you allocate with new T() it is a horrible error to delete with
delete []
Yes. That number is obviously available to (and needed by) the
compiler.
>
> Similar to that, in
>
> delete [] p;
>
> compiler knows that it should call ~TYPE() on "count" instances of
> TYPE, and does that.
This is not necessarily true. If the type has a rivial destructor,
there is no need for the compiler to know about the number of
elements.
>
> Note also: if what you are saying were true, we would have to do e.g.
>
> delete [count, sizeof(TYPE)] p;
You did have to do so (except for the sizeof(TYPE) which is not needed
in any case) in pre-standard C++.
But the core of the matter is that in delete p the compiler knows
there is only one element whereas in delete[] p, there will (usually)
be more than one. In cases where the destructor is non-trivial, the
compiler will need to know the count. Otherwise it will not.
/Peter
No, I'm not mistaken.
> Compiler
> knows sizeof(TYPE) and the size of the allocated heap block.
No, it doesn't know the size of the allocated heap block.
> So, in
>
> TYPE* p = new TYPE[count];
>
> compiler knows that it should allocate space of count*sizeof(TYPE)
> octets.
Yes, but 'count' is a run-time quantity, as in
TYPE* p = new TYPE[rand()];
for example. So, you statement about something the compiler "knows" here
is absolutely incorrect. The compiler does not know and cannot know how
many elements are in the array in general case.
> Similar to that, in
>
> delete [] p;
>
> compiler knows that it should call ~TYPE() on "count" instances of
> TYPE, and does that.
No, the compiler doesn't know anything like that in this case.
Everything in this case is a run-time property or a run-time quantity.
The only thing the compiler "knows" is the format in which this run-time
quantity is preserved by 'new[]' in order to be retrieved by 'delete[]'
later, but that's a completely different thing.
Please, don't distort the nature of the question asked by the original
poster and the meaning of the terms used there. The OP made it perfectly
clear that the words "compiler knows <something>" in his post are
intended to mean that "<something> is known at compile-time". He makes
an assertion that the array size is always known at compile-time. This
is what I address in my response. The OP's assertion is incorrect. The
required parameters (like array size) are _not_ known at compile-time,
which is what I mean when I say that the compiler does not know that.
This, I believe, is perfectly clear from the OP's post and from my post.
--
Best regards,
Andrey Tarasevich
[ See http://www.gotw.ca/resources/clcm.htm for info about ]