views:

512

answers:

10

Possible Duplicate:
( POD )freeing memory : is delete[] equal to delete ?

Does delete deallocate the elements beyond the first in an array?

char *s = new char[n];
delete s;

Does it matter in the above case seeing as all the elements of s are allocated contiguously, and it shouldn't be possible to delete only a portion of the array?

For more complex types, would delete call the destructor of objects beyond the first one?

Object *p = new Object[n];
delete p;

How can delete[] deduce the number of Objects beyond the first, wouldn't this mean it must know the size of the allocated memory region? What if the memory region was allocated with some overhang for performance reasons? For example one could assume that not all allocators would provide a granularity of a single byte. Then any particular allocation could exceed the required size for each element by a whole element or more.

For primitive types, such as char, int, is there any difference between:

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

Except for the routes taken by the respective calls through the delete->free deallocation machinery?

+1  A: 

For primitive types, such as char, int, is there any difference between:

I'd say you'll get undefined behaviour. So you shouldn't count on stable behaviour. You should always use new/delete, new[]/delete[] and malloc/free pairs.

big-z
No,m "implementation defined" is the term used by ISO when a compiler vendor must document their choice. There's no such obligation in this case. Nasal deamons are allowed without warning.
MSalters
It has been already discussed here: http://stackoverflow.com/questions/1553382/-pod-freeing-memory-is-delete-equal-to-delete
Naveen
I didn't know that such term used by ISO. Fixed.
big-z
+1  A: 

It's undefined behavior. Hence, the anser is: yes, there could be danger. And it's impossible to predict exactly what will trigger problems. Even if it works one time, will it work again? Does it depend on the type? Element count?

MSalters
+10  A: 

It's undefined behaviour (most likely will corrupt heap or crash the program immediately) and you should never do it. Only free memory with a primitive corresponding to the one used to allocate that memory.

Violating this rule may lead to proper functioning by coincidence, but the program can break once anything is changed - the compiler, the runtime, the compiler settings. You should never rely on such proper functioning and expect it.

delete[] uses compiler-specific service data for determining the number of elements. Usually a bigger block is allocated when new[] is called, the number is stored at the beginning and the caller is given the address behind the stored number. Anyway delete[] relies on the block being allocated by new[], not anything else. If you pair anything except new[] with delete[] or vice versa you run into undefined behaviour.

sharptooth
+10  A: 

Read the FAQ: 16.3 Can I free() pointers allocated with new? Can I delete pointers allocated with malloc()?

Does it matter in the above case seeing as all the elements of s are allocated contiguously, and it shouldn't be possible to delete only a portion of the array?

Yes it does.

How can delete[] deduce the number of Objects beyond the first, wouldn't this mean it must know the size of the allocated memory region?

The compiler needs to know. See FAQ 16.11

Because the compiler stores that information.

What I mean is the compiler needs different deletes to generate appropriate book-keeping code. I hope this is clear now.

dirkgently
If the compiler stores information required for delete[], why can't it be smart enough to work with plain delete?
vanja.
"Because the compiler stores that information." that's a load of nonsense. does operator new keep duplicates of all the allocations with the element count for array allocations? no that seems unlikely and very inefficient to me.
Matt Joiner
@Anacrolix: I refer to book-keeping information that the compiler does manage for allocations/deallocations. I am not sure what you mean by duplicates. VS used to keep the number of array elements just before the start of the array. Can you provide alternate implementations?
dirkgently
@vanja: For a simple new/delete, much less book-keeping information is required. For arrays, on the other hand, the compiler has to allocate a bit more than what you will use.
dirkgently
@vanja: If you were to use the vanilla delete for both pointer to a single object and a pointer to an array of objects, the compiler wouldn't know one from the other. FAQ 16.11
dirkgently
It's not the compiler that stores that information, it's the run-time. Please update your answer, the difference is important. The compiler cannot store that information because it's not known at compile time.
sbk
@dirkgently: actually since you can override the new/delete operators, you can store the information as you which. Effectively, most implementation store the size of the array just before the first element so you can usually find it with a small (negative) offset.
Matthieu M.
+4  A: 

Yes, this is dangerous!

Dont do it!

It will lead to programm crashes or even worse behavior!

For objects allocated with new you MUST use delete;

For objects allocated with new [] you MUST use delete [];

For objects allocated with malloc() or calloc() you MUST use free();

Be aware also that for all these cases its illegal to delete/free a already deleted/freed pointer a second time. free may also NOT be called with null. calling delete/delete[] with NULL is legal.

RED SOFT ADAIR
this is well known. i'm asking about specific cases.
Matt Joiner
""free() frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is NULL, no operation is performed. """. Note the clause about null. From http://linux.die.net/man/3/free, but I don't have a formal C specification handy.
pst
there are no specific cases. It... is.... not.... allowed.
jalf
+3  A: 

Yes, there's a real practical danger. Even implementation details aside, remember that operator new/operator delete and operator new[]/operator delete[] functions can be replaced completely independently. For this reason, it is wise to think of new/delete, new[]/delete[], malloc/free etc. as different, completely independent methods of memory allocaton, which have absolutely nothing in common.

AndreyT
Even if they can be replaced independently, it usually advised to either replace all of them (comprising placement new) or none at all.
Matthieu M.
Yes, maybe. But even if they all are replaced, they still can allocate memory from different memory pools with different memory management principles (for obvious reasons, like block sizes in '[]' functions are variadic even for the same object type, while in non-'[]' functions they are not), thus making any cross-use completely infeasible.
AndreyT
A: 

Although it might seem in some logic way that you can mix new[] and free or delete instead of delete[], this is under the assumption about the compiler being a fairly simplistic, i.e., that it will always use malloc() to implement the memory allocation for new[].

The problem is that if your compiler has a smart enough optimizer it might see that there is no "delete[]" corresponding to the new[] for the object you created. It might therefore assume that it can fetch the memory for it from anywhere, including the stack in order to save the cost of calling the real malloc() for the new[]. Then when you try to call free() or the wrong kind of delete on it, it is likely to malfunction hard.

Paul Hsieh
+1  A: 

Does delete deallocate the elements beyond the first in an array?

No. delete will deallocate only the first element regardless on which compiler you do this. It may work in some cases but that's co-incidental.

Does it matter in the above case seeing as all the elements of s are allocated contiguously, and it shouldn't be possible to delete only a portion of the array?

Depends on how the memory is marke as free. Again implementation dependant.

For more complex types, would delete call the destructor of objects beyond the first one?

No. Try this:

#include <cstdio>

class DelTest {
    static int next;
    int i;
public:
    DelTest() : i(next++) { printf("Allocated %d\n", i); }
    ~DelTest(){ printf("Deleted %d\n", i); }
};

int DelTest::next = 0;

int main(){
    DelTest *p = new DelTest[5];
    delete p;
    return 0;
}

How can delete[] deduce the number of Objects beyond the first, wouldn't this mean it must know the size of the allocated memory region?

Yes, the size is stored some place. Where it is stored depends on implementation. Example, the allocator could store the size in a header preceding the allocated address.

What if the memory region was allocated with some overhang for performance reasons? For example one could assume that not all allocators would provide a granularity of a single byte. Then any particular allocation could exceed the required size for each element by a whole element or more.

It is for this reason that the returned address is made to align to word boundaries. The "overhang" can be seen using the sizeof operator and applies to objects on the stack as well.

For primitive types, such as char, int, is there any difference between ...?

Yes. malloc and new could be using separate blocks of memory. Even if this were not the case, it's a good practice not to assume they are the same.

Vulcan Eager
I think you mean new and malloc could be using different allocators?
Matt Joiner
There can be additional "overhang". Alignment has to do with the starting address of the block. It is possible that for performance reasons, an allocator uses more memory. For instance, there are allocators that only allocate blocks with sizes that are a power of 2. If you ask for 33 bytes, you get a block of size 64. This makes managing the list of allocated and free blocks much easier/faster, at the expense of increased memory use. It may even be possible for the allocator to know the size of the allocation from just the starting address, negating the need to store additional information.
KeithB
Vulcan Eager
+2  A: 

Raymond Chen (Microsoft developer) has an in-depth article covering scaler vs. vector deletes, and gives some background to the differences. See:

http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx

Aledh
A: 

Step 1 read this: what-is-the-difference-between-new-delete-and-malloc-free

You are only looking at what you see on the developer side.
What you are not considering is how the std lib does memory management.

The first difference is that new and malloc allocate memroy from two different areas in memory (New from FreeStore and malloc from Heap (Don't focus on the names they are both basically heaps, those are just there offical names from the standard)). If you allocate from one and de-allocate to the other you will messs up the data structures used to manage the memory (there is no gurantee they will use the same structure for memory management).

When you allocate a block like this:

int*   x= new int; // 0x32

Memory May look like this: It probably wont since I made this up without thinking that hard.

Memory   Value      Comment
0x08     0x40       // Chunk Size  
0x16     0x10000008 // Free list for Chunk size 40
0x24     0x08       // Block Size
0x32     ??         // Address returned by New.
0x40     0x08       // Pointer back to head block.
0x48     0x0x32     // Link to next item in a chain of somthing.

The point is that there is a lot more information in the allocated block than just the int you allocated to handle memory management.

The standard does not specify how this is done becuase (in C/C++ style) they did not want to inpinge on the compiler/library manufacturers ability to implement the most effecient memory management method for there architecture.

Taking this into account you want the manufacturer the ability to distinguish array allocation/deallocation from normal allocation/deallocation so that it is possable to make it as effecient as possable for both types independantly. As a result you can not mix and match as internally they may use different data structures.

If you actually analyse the memory allocation differences between C and C++ applications you find that they are very different. And thus it is not unresonable to use completely different techniques of memory management to optimise for the application type. This is another reason to prefer new over malloc() in C++ as it will probably be more effecient (The more important reason though will always be to reducing complexity (IMO)).

Martin York