how are `delete[] obj` and `delete obj` implemented at compiler level [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why [] is used in delete ( delete [] ) to free dynamically allocated array?
Why does C++ still have a delete[] AND a delete operator?
I'm wondering what's their difference and I know the obvious answer some might say, that one is to delete an array and the other is to delete a single object but I'm wondering why should there be two different deletion methods for these two operations? I mean delete is basically implemented using C free method which doesn't care if the pointer is actually pointing toward an array or a single object. The only reason I can think of is two be able to know if it's an array and call destructor for each cell instead of only the first object but that wouldn't also be possible since compiler can not guess the length of array just looking at it's pointer. By the way though it's said to invoke undefined behavior to call delete for memory allocated with new[] I can't imagine anything that could possibly go wrong.

As you have discovered the compiler needs to know the length of an array (at least for non-trivial types) to be able to call destructors for each element. For this new[] typically allocates some extra bytes to record the element count and returns a pointer to the end of this bookkeeping area.
When you use delete[] the compiler will look at the memory before the array to find the count and adjust the pointer, so that the originally allocated block is freed.
If you use delete to destroy a dynamically allocated array, destructors for elements (except the first) won't be called and typically this will end up attempting to free a pointer that doesn't point to the beginning of an allocated block, which may corrupt the heap.

but that wouldn't also be possible since compiler can not guess the
length of array just looking at it's pointer
That's not really true. The compiler itself doesn't need to guess anything, but it does decide which function to call to free the memory based on the operator it sees. There is a separate function dedicated to releasing arrays, and this function does indeed know the length of the array to be freed so it can appropriately call destructors.
It knows the length of the array because typically new[] allocates memory that includes the array length (since this is known on allocation) and returns a pointer to just the "usable" memory allocated. When delete[] is called it knows how to access this memory based on the pointer to the usable part of the array that was given.

When you allocate memory using new[], the compiler not only needs to construct each element, it also needs to keep track of how many elements have been allocated. This is needed for delete[] to work correctly.
Since new and delete operate on scalars, they don't need to do that, and could save on a little bit of overhead.
There is absolutely no requirement for new to be compatible with delete[] and vice versa. Mixing the two is undefined behaviour.

Related

Why two operators for deleting dynamically allocated memory? [duplicate]

This question already has answers here:
Why do we even need the "delete[]" operator?
(7 answers)
Closed 8 years ago.
This question may sound a bit weird, but I never entirely got why do we need to have 2 different syntax for deleting dynamically allocated memory in C++?
For example,
int *p = new int[10];
delete[] p; // why not just delete p;?
In plain old C, you just use the free function to release the memory allocated for a pointer, regardless of the number of elements allocated. Of course, C++ is a bit more complicated, as it allows for class types, which invoke their destructor etc. However, I see no impediment in using a single syntax for deleting dynamically allocated memory in C++.
Is there any fundamental reason why it was decided to use 2 versions, delete and delete[]?
More than that, most compilers do not even warn you if you use delete instead of delete[], and this creates undefined behaviour.
The underlying reason is that arrays don't have destructors. But arrays are still objects. Therefore, when arrays are allocated dynamically, they require special treatment. A pointer to an object is indistinguishable from a pointer to the first element of an array, so you need a special language construct to indicate that the pointer points into an array, and that multiple array elements need to have their destructors called.
An expression with the delete[] operator, first calls the appropriate
destructors for each element in the array (if these are of a class
type), and then calls an array deallocation function.
From here
The language allows you to overload the underlying allocation and deallocation functions. You might want to do this differently for single objects and for arrays; having two different operators allows you to do that.

How does delete[] know how much memory to delete? [duplicate]

This question already has answers here:
How does delete[] "know" the size of the operand array?
(9 answers)
How does delete[] know it's an array?
(16 answers)
Closed 9 years ago.
int* i = new int[4];
delete[] i;
While we call delete[], how does the program know "i" is 4 byte-length. Is 4 be stored in somewhere in memory?
The implementation of delete[] depend on System or Compilers?
Is there some System API to get the length of i?
As HadeS said, which will hold the information how much memory has been allocated? And where?
It must be hold in memory, or maybe nearby the pointer i.
First off, i is not "4-byte length". Rather, i is a pointer to an array of four ints.
Next, delete[] doesn't need to know anything, because int has no destructor. All that has to happen is that the memory needs to be freed, which is done by the system's allocator. This is the same situation as with free(p) -- you don't need to tell free how much memory needs to be freed, since you expect it to figure that out.
The situation is different when destructors need to be called; in that case, the C++ implementation does indeed need to remember the number of C++ objects separately. The method for this is up to the implementation, although many compilers follow the popular Itanium ABI, which allows linking together of object code compiled by those different compilers.
There is no way for you to query this information. You should consider dynamic arrays a misfeature of C++; there is essentially no reason to use them*, and you can always do better with some kind of class that manages memory and object separately and individually: Since you'll have to remember the number of array elements anyway, it's much better to encapsulate the size and the allocation in one coherent class, rather than have vague dynamic arrays that you cannot really use without passing extra information along anyway (unless you had self-terminating semantics, but then you'd just be using the extra space for the terminator).
*) And there are at least two standard defects about dynamic arrays that nobody is too bothered to worry about fixing
When you dynamically allocate a memory; compiler allocates an extra block of memory apart from what you have asked, which will hold the information how much memory has been allocated.
when you try to delete this memory using delete this extra block of memory will be read by the compiler to see how much memory was allocated and free the space accordingly.
I don't think there is any API which will fetch this information.

How does delete[] keep track of the number of elements? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does delete[] “know” the size of the operand array?
How does the delete in C++ know how many memory locations to delete
I know it's a rather simple question but I a not sure about the difference (if any) between this lines :
double * a = new double[100];
delete[] a;
delete a;
free ((void*)a);
First off, would all of these calls (used each without the others) work the same way and free sizeof(double)*100 bytes?
Which lead me to the 2nd question, how does the program keep track of the size of the allocated memory? For instance if I send my a pointer to a function, then delete[] this pointer from within my function, would I also free the same amount of memory?
Thanks
The difference, oversimplified, is this:
delete[] a;
Is correct. All others are incorrect, and will exhibit Undefined Behavior.
Now, in reality, on all the compilers I use daily, delete a; will do the right thing every time. But you should still not do it. Undefined Behavior is never correct.
The free call will also probably do the right thing in the real world, but only because the thing you're freeing doesn't have a non-default destructor. If you tried to free something that was a class with a destructor, for example, it definitely wouldn't work -- the destructor would never be called.
That's one of the big differences (not the only difference) between new/delete and malloc/free -- the former call the constructors and destructors, while the latter meerly allocate and dealocate space.
Incorporating something #Rob said in his now-deleted post:
The simple rule is this: every new[] requires exactly one delete[].
Every new requires exactly one delete. malloc requires free. No
mix-and-match is allowed.
As to the question of how delete[] knows how many elements to delete, please see this response to a previous duplicate question.
Someone correct me, if I'm wrong, but as far as I understand, you use delete when you previously allocated memory with new and delete[] after using new Type[]. And free is used when you have allocated memory using malloc.
See c++ reference on delete and free.
Regarding the array of doubles, the result of all forms is the same -- all the allocated memory is returned to the system. The difference in calling free vs. delete vs. delete[] is:
free only releases the memory (the size of memory allocated for a was stored by memory manager when calling new)
delete calls the destructor of allocated object before releasing the memory
delete[] calls the destructor of each element in the array before releasing the memory
The difference is important if destructor of the allocated object contains cleanup code which releases other memory or system resource such as file or socket descriptor allocated during the lifetime of an object.
It is a good habit in C++ to allways use deleteon single instances and delete[] on array of objects/primitives regardless of the content of destructor.

Is there any danger in calling free() or delete instead of delete[]? [duplicate]

This question already has answers here:
Closed 13 years ago.
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?
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.
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.
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.
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.
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
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.
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?
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.
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.
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 official 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)).

Why is there a special new and delete for arrays?

What is wrong with using delete instead of delete[]?
Is there something special happening under the covers for allocating and freeing arrays?
Why would it be different from malloc and free?
Objects created with new[] must use delete[]. Using delete is undefined on arrays.
With malloc and free you have a more simple situation. There is only 1 function that frees the data you allocate, there is no concept of a destructor being called either. The confusion just comes in because delete[] and delete look similar. Actually they are 2 completely different functions.
Using delete won't call the correct function to delete the memory. It should call delete[](void*) but instead it calls delete(void*). For this reason you can't rely on using delete for memory allocated with new[]
See this C++ FAQ
[16.13] Can I drop the [] when
deleteing array of some built-in type
(char, int, etc)?
No!
Sometimes programmers think that the
[] in the delete[] p only exists so
the compiler will call the appropriate
destructors for all elements in the
array. Because of this reasoning, they
assume that an array of some built-in
type such as char or int can be
deleted without the []. E.g., they
assume the following is valid code:
void userCode(int n) {
char* p = new char[n];
...
delete p; // ← ERROR! Should be delete[] p !
}
But the above code is wrong, and it
can cause a disaster at runtime. In
particular, the code that's called for
delete p is operator delete(void*),
but the code that's called for
delete[] p is operator
delete[](void*). The default behavior
for the latter is to call the former,
but users are allowed to replace the
latter with a different behavior (in
which case they would normally also
replace the corresponding new code in
operator new[](size_t)). If they
replaced the delete[] code so it
wasn't compatible with the delete
code, and you called the wrong one
(i.e., if you said delete p rather
than delete[] p), you could end up
with a disaster at runtime.
Why does delete[] exist in the first place?
Whether you do x or y:
char * x = new char[100];
char * y = new char;
Both are stored in char * typed variables.
I think the reason for the decision of delete, and delete[] goes along with a long list of decisions that are in favor of efficiency in C++. It is so that there is no enforced price to do a lookup of how much needs to be deleted for a normal delete operation.
Having 2 new and new[] seems only logical to have delete and delete[] anyway for symmetry.
The difference is that delete will only delete the entire memory range, but will only call the destructor for 1 object. delete[] will both delete the memory and call the destructor for every single object. If you do not use delete[] for arrays, it's only a matter of time before you introduce a resource leak into your application.
EDIT Update
According to the standard, passing an object allocated with new[] to delete is undefined. The likely behavior is that it will act as I described.
Stroustrup talks about the reasons for separate new/new[] and delete/delete[]` operators in "The Design and Evolution of C++" in sections 10.3 through 10.5.1:
10.3 Array Allocation - discusses that they wanted a way to allow arrays of objects to be allocated using a separate scheme from allocation single objects (ie., allocating arrays from a separate store). Adding the array versions of new and delete was a solution for this;
10.5.1 Deallocating Arrays - discusses how a problem with deallocating arrays using just a single delete operator is that there needs to be more information than just the pointer in order to determine if the pointer points to the first element of an array or if it just points to a single object. Instead of "complicating the common case of allocating and deallocating individual objects", the delete[] operator is used to handle arrays. This fits in with the general C++ design philiosophy of "don't pay for what you don't use".
Whether this decision was a mistake or not is debatable - either way has good arguments, but we have what we have.
The reason for this requirement is historical and because new type and new type [size] return different things that need to be cleaned up differently.
Consider this code
Foo* oneEntry = new Foo;
Foo* tenEntries = new Foo[10];
These both return a Foo* pointer, the difference is the second call will result in the Foo constructor being called 10x, and there being roughly 10x as much memory.
So now you want to free your objects.
For a single object you would call delete - e.g. delete oneEntry. This calls the objects destructor and and deallocates the memory.
But here's the problem - oneEntry and tenEntries are both just Foo pointers. The compiler has no idea whether they point to one, ten, or a thousand elements.
When you use the special syntax of delete []. This tells the compiler "this is an array of objects, figure out the count and then destruct them all".
What really happens is that for new type [size] the compiler secretly stores 'size' somewhere else. When you call delete[] it knows that this secret value exists so it can find out how many objects are in that block of memory and destruct them.
The question you could then ask is "why doesn't the compiler always store the size?"
That's a great question and it dates back to the early days of C++. There was a desire that for built-in types (char, int, float, etc) the following would be valid for C++;
int* ptr = new int;
free(ptr);
int* ptr = (int*)malloc(sizeof(int) * someSize);
delete ptr;
The reasoning behind this was an expectation that people would provide libraries that returned dynamically allocated memory, and users of these libraries would have no way of knowing whether to use free/delete.
This desire for compatibility meant that the size of an array could not be stored as part of the array itself and had to be kept elsewhere. Because of this overhead (and remember, this was back in the early 80's) it was decided to do this book keeping only for arrays and not single-elements. Thus arrays need a special delete syntax that looks up this value.
The reason malloc/free do not have this problem is that they simply deal with blocks of memory and do not have to worry about calling constructors/destructors.
As to the "why" in the title: one of the design goals of C++ was that there wouldn't be any hidden costs. C++ was also developed at a time when every byte of memory still mattered a whole lot more than it does today. Language designers also like orthogonality: if you allocate the memory with new[] (instead of new), you should free it with delete[].
I don't think there's any technical reason that new[] couldn't stick an "I'm an array" flag in the header of the memory block for delete (no more delete[]) to look at later.
new and delete are different from malloc and free in that malloc and free only allocate and free memory; they don't call ctors or dtors.
When you use new[] to allocate an array, you are actually telling C++ the size of the array. When you use malloc, you are instead telling it how much memory is allocated. In the former case, freeing based on the size of the array would not make sense. In this case, it does. But since there is no difference between a pointer for an array vs. for a single object, a separate function is needed.