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

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.

Related

Logic in C++'s delete and delete[] [duplicate]

This question already has answers here:
Is delete[] equal to delete?
(6 answers)
Closed 9 years ago.
In C, free() is used to release the memory, say free(ptr). As I understand, extra memory is allocated before ptr in the library code to store the block size information. After free() is called, the whole block is tracked and then released.
In C++, there are two forms of new and delete. One is for array. If new[] is used, delete[] should be used. For example,
int ptr = new [10];
delete [] ptr;
Question 1: can I use delete ptr here? If that is OK, what if delete ptr + 2?
Question 2: If delete[] has to be used to match new[], why do we need two forms of delete? Just one form, say delete, would be enough.
Thanks for all the suggestions!
Thank Mgetz. Question 2 should be: why c++ standard proposed both delete [] and delete if there is only one correct form at any situation?
Q1: You can use delete, but it is wrong.
This will usually "work" insofar as it will correctly free the allocated memory, but it will not call destructors properly. For trivial types, you will often not see any difference, but that doesn't mean it isn't wrong anyway. In any case it is undefined behavior which you should avoid if you can (invoking UB forfeits any guarantees that your code will work, it might of course still work, but you can never be 100% sure).
Deleting ptr+2 is also undefined behavior and will almost certainly not "work", not even a little. Usually, this will simply result in a program crash.
Q2: You need the two because they mean different things. One means "delete this pointer-to-single-object" whereas the other means "delete this pointer-to-array-of-objects".
Obviously, the compiler needs to generate different code for those different things.
You need the two forms because, unlike malloc and free, new and delete do more than just allocate and deallocate memory; they also construct and destruct the object(s) respectively.
new and delete deal with scalar objects, while new[] and delete[] deal with arrays of objects.
When you call new T[n], it'll allocate enough memory for n copies of T, and then construct n instances within the allocated memory. Similarly, calling delete[] will cause destruction of those n instances followed by deallocation.
Obviously, since you do not pass n to delete[] that information is being stashed away somewhere by the implementation, but the standard doesn't require an implementation to destroy all n objects if you call delete instead. The implementation could just destroy the first object, it might behave correctly and destroy all n objects or it might cause demons to fly out of your nose.
Simply put, it's undefined behavior, there's no telling what'll happen, it's best imperative you avoid it.

C++ delete array memory without brackets still works? [duplicate]

This question already has answers here:
Is delete[] equal to delete?
(6 answers)
how to properly delete a pointer to array
(6 answers)
How do I use arrays in C++?
(5 answers)
dynamically allocated string arrays failed to be deallocated
(2 answers)
Closed 9 years ago.
int* arr = new int[count];
delete arr;
Why does this work? I've checked and it actually frees the memory. From what I've read I need delete[] arr; otherwise it won't actually free all the memory.
The difference is not whether or not the allocated memory is properly freed - whether you use
delete
or
delete[]
the memory will still be properly deallocated.
The difference is whether or not the destructors will be properly invoked.
delete // will only invoke the destructor of the first element of the array.
delete[] // will invoke the destructor for *each* element of the array.
This has no practical effect for primitive types like int or float, but when you have an array of some class, the difference can be critical.
Now try it with filling the array with strings of 100 bytes each, and see if it still frees all the allocated memory...
It is undefined behaviour, and as always, sometimes UB will appear to work. In your case, you have no destructor for the objects in the memory, so there is no "further work", just free all the memory [1]. But if you have an object that has a destructor that does something useful, it (probably) won't get called.
You should ALWAYS use delete [] if you used new T[size]; to allocate. Don't mix the two, it's always wrong - just sometimes it HAPPENS to work [just like SOME sizes of spanners in inches works on mm nuts and vice versa - but it's still wrong to use a inches spanner set on metric nuts].
[1] Note that this may work for this particular compiler/C++ library combination. Compiling it with a different compiler, using a different C++ library, or compiling for a different OS may cause it to crash when you try the same thing.
delete and delete [] are actually different operators and to use the wrong one is always an error. The problem is that it often seems fine at the time, but the heap has ben corrupted and you are very likely to experience an apparently unrelated crash later.

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

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.

Differences between `malloc` and `new` [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
What is the difference between new/delete and malloc/free?
Could someone please revise/edit the below - the differences between malloc and new - and see if everything is correct, or am I missing something or got something wrong? Thank you,
Both malloc and new are used for Dynamic Memory Allocation.
malloc is a C function, whereas new is a C++ operator.
malloc requires a special typecasting when it allocates memory dynamically,
whereas new does not require any typecasting.
Whenever we use new for allocating memory, it also invokes any required constructors, whereas malloc doesn't do that.
malloc can fail and returns a NULL pointer if memory is exhausted, whereas new never returns a NULL pointer, but indicates failure by throwing an exception instead.
While using malloc, free is the C function used to free up the allocated memory.
While using new, delete is the C++ operator used to free up the allocated memory AND call any required destructors.
Important things to note and remember:
placement new
delete[]
_set_new_handler() function
I would like to add the following with your differences,
malloc" does is allocate memory and return a pointer to it. For whatever reason, the designers of the C language implemented it as a standard library function.
On the Other hand "new" is to instantiate an object, by allocating memory and calling the appropriate constructors. Seems reasonable to me that this function is far more tied to the language than something that simply allocates storage.
new calls constructors, while malloc() does not. In fact primitive data types (char, int, float.. etc) can also be initialized with new.
It looks ok, but you could stress the fact that you should never mix malloc with delete and new with free.
Don't forget new[] and delete[], for array allocation and deallocation respectively.

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.