views:

10756

answers:

11

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(2);
     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)

+24  A: 

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 FAQ Lite.

Fred Larson
Actually, using delete[] to delete something created with new is exploitable. http://taossa.com/index.php/2007/01/03/attacking-delete-and-delete-in-c/#comment-63884
Rodrigo
+1  A: 

It doesn't know it's an array, that's why you have to supply delete[] instead of regular old delete.

eduffy
+3  A: 

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.

Uri
+7  A: 

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);
JaredPar
+9  A: 

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.

bsdfish
+1 - valid point in general except that usually the language runtime is responsible for storing this metadata, not the OS.
sharptooth
+7  A: 

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.

Dan Breslau
"fussiness about a few extra bytes of memory seems quaint these days". Fortunately, to such people bare arrays are also starting to look quaint, so they can just use a vector or boost::array, and forget about delete[] forever :-)
Steve Jessop
+1 for useful background info.
j_random_hacker
A: 

You cannot delete for an array, and you cannot use delete [] for a non-array.

+1  A: 

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.

Benoît
A: 

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.

ProdigySim
A: 

Simply, it does not know. Semantically, both versions of delete operator in C++ can eat any pointer, however if pointer to array is given to delete[], it will result in UB, meaning it may crash or completely nothing may happen.

C++ requires programmer to proper version of the delete operator depending on subject of deallocation: array or single object.

If compiler could automatically determine that a pointer passed to delete operator is a pointer array and vice versa, then there was only one delete operator designed in to C++ as it would be no longer necessary to choose one of them explicitly.

mloskot
A: 
sharkboy