Why can't I delete pointer alone from an array of objects? - c++

A* p = new A[5];
delete &p[2];
// error,why? Does it need to use delete []p to delete together?
p is a pointer(p == &p[0]),however, p[0],p[1]... is a type of object. why p[n] is not pointer?

What you delete has to exactly match what you allocated, you can't do partial deletions. The memory manager generally records information about the allocation based on the address that it returned. If you pass a different address to delete, it won't be able to find the allocation information.

What would that achieve? You're trying to free the space of a single A, somewhere in the middle of a longer contiguous array of A's.
This simply doesn't work because it's against what delete does.
when you do new[], your runtime gets you a sufficiently large set of memory to store the array of objects. If that memory isn't "lying around" anyways, the runtime asks the operating system to map memory pages into your processes' memory space.
Now, if you no longer use these pages, you can "give them back"; but, you must do that to the whole chunk of memory you got. That's because freeing less than a page can't work (because the OS can't assign it anywhere else), and because allowing for this kind of fragmentation would make page tables huge.
this is reflected in the documentation of free: You can only free memory by handing free the exact same address malloc gave you.

Yes and no:
Yes, a call to new[] must be paired with a single call to delete[].
No, that does not "delete together", as the result is just one entity (an array), not a collection of As. Therefore, you do not actually delete anything together.
No, you need not end the lifetime of all elements of the array at the same time. However, explicitly calling an destructor is something you might wish to leave to standard library components at this point.
Which brings us to:
What you seem to want to achieve:
End the lifetime of a single object of that array. Since it does not make any sense for the result to be an array with some kind of magic hole, you might want to consider std::vector<A>::erase to deal with it. This will remove one element and move up all other elements so that the result behaves like an array where one element has been removed without leaving a hole.

delete works on pointers (and only pointers to dynamically allocated memory blocks) but you don't have an array of pointers, so delete doesn't work on the array elements, it can only work on the array pointer. And it should be the delete [] operator in particular.
If you want to remove an element from the array, you must iterate the array, and when you reach the element you want to remove, start overwriting the array with the next element. Also, you might want to allocate a new, shorter array, and do that operation there, then delete the old array and set the array pointer to the new array.
Ideally, you should use an std::vector class, which does everything for you automatically:
std::vector<A> v(5); // gives you a vector of 5 A elements
v.erase(v.begin() + 2); // erases the element at index 2
This way is less prone to errors and is preferred, and is just as fast and efficient as the error-prone manual way.
Now if you had an array/vector of pointers to elements, that would be a different matter, then you'd have to make sure you delete the element and erase it from the vector. Naturally, if you use smart pointers, you can simply erase the pointer from the vector and it will be automatically deleted.
why p[n] is not pointer?
The [n] operator for pointers is just a shortcut to deference a pointer with an offset. So p[2] is equivalent to *(p + 2). And when you dereference a pointer, you get a reference to whatever it points to, in your case an A instance. So delete p[2] can only work if it is an array of A pointers, not A instances. Note that in your case &p[2] will actually be a pointer, it will be the same value as p + 2 because the & operator will take the address of the reference, but you should not use delete on it, as it itself doesn't point to dynamcally allocated memory, even if it itself happens to be in such memory.
As you yourself noted in the question p == &p[0] but nonetheless, p != p[0]. This means neither should you delete &p[0] even if both are pointers to the same address. Since the memory for the array has been allocated with new [] it should be deallocated with delete [], and you should not use the delete operator on the array or any of its elements.
&p[0] gives you the address of the first element in the array, which coincides with the beginning of the array, but p == &p[0] is just a value comparison. p may be "equal" to &p[0] but it is not the same semantically, as p is a pointer to A [] and &p[0] is a pointer to A.

Related

Can you delete a C-array of 1 integer as you would a normal integer?

If I have a C-array T* name = new T[1];, can I delete it like this: delete name; since it only has 1 element, or is it undefined behaviour?
Or, to generalize the question, when you have an array T* arr = new T[x];, if you delete arr;, does it only delete the first element of the array, or does it depend from compiler to compiler?
You have to delete it with delete[] name.
You always must match new with delete and new[] with delete[]. Mixing them will result in undefined behaviour.
T arr[x];
is something else entirely, it's an array with automatic storage duration. The memory will be automatically released when it goes out of scope. Trying to delete it will result in undefined behaviour.
And lastly there is no such thing as "deleting only the first element", when you allocate a block of memory, no matter how large it is, you muss deallocate the whole block.
Anyway, that's were standard containers like std::vector come in to make your life easier and hide all the complexity of memory (de-)allocation.
In order for the compiler to be able to use delete[] on an array, it would need to invoke the destructor of every element. This would require that it to know not only the address of the first element (which it would get from the pointer) and the stride (which can be inferred from the element type), but also the number of elements. To accommodate this, it is necessary to allocate space not only for the elements, but also for some kind of integer value indicating how many there are. Thus, new[] would typically allocate slightly more space than needed to hold all the array elements, stores the count at the start of that space, and returns a pointer the portion of the allocation after the count. Calling delete[] would subtract the size of the header from the supplied pointer, use the resulting pointer to retrieve the count, call the destructor on the appropriate number of array elements, and then delete the allocation that contained all of them.
While the exact details of how the count is stored will vary among different implementations, an understanding of the general principle should make it clear why the Standard makes no attempt to specify the effects of combining array new[] and non-array delete, or combining non-array new and array delete[].

How does the compiler/program deduces the size of memory to be deleted(released) in case of delete[] arr; [duplicate]

Foo* set = new Foo[100];
// ...
delete [] set;
You don't pass the array's boundaries to delete[]. But where is that information stored? Is it standardised?
When you allocate memory on the heap, your allocator will keep track of how much memory you have allocated. This is usually stored in a "head" segment just before the memory that you get allocated. That way when it's time to free the memory, the de-allocator knows exactly how much memory to free.
ONE OF THE approaches for compilers is to allocate a little more memory and to store a count of elements in a head element.
Example how it could be done:
Here
int* i = new int[4];
compiler will allocate sizeof(int)*5 bytes.
int *temp = malloc(sizeof(int)*5)
Will store "4" in the first sizeof(int) bytes
*temp = 4;
and set i
i = temp + 1;
So i will points to an array of 4 elements, not 5.
And deletion
delete[] i;
will be processed in the following way:
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)
The information is not standardised. However in the platforms that I have worked on this information is stored in memory just before the first element. Therefore you could theoretically access it and inspect it, however it's not worth it.
Also this is why you must use delete [] when you allocated memory with new [], as the array version of delete knows that (and where) it needs to look to free the right amount of memory - and call the appropriate number of destructors for the objects.
It's defined in the C++ standard to be compiler specific. Which means compiler magic. It can break with non-trivial alignment restrictions on at least one major platform.
You can think about possible implementations by realizing that delete[] is only defined for pointers returned by new[], which may not be the same pointer as returned by operator new[]. One implementation in the wild is to store the array count in the first int returned by operator new[], and have new[] return a pointer offset past that. (This is why non-trivial alignments can break new[].)
Keep in mind that operator new[]/operator delete[]!=new[]/delete[].
Plus, this is orthogonal to how C knows the size of memory allocated by malloc.
Basically its arranged in memory as:
[info][mem you asked for...]
Where info is the structure used by your compiler to store the amount of memory allocated, and what not.
This is implementation dependent though.
This isn't something that's in the spec -- it's implementation dependent.
Because the array to be 'deleted' should have been created with a single use of the 'new' operator. The 'new' operation should have put that information on the heap. Otherwise, how would additional uses of new know where the heap ends?
This is a more interesting problem than you might think at first. This reply is about one possible implementation.
Firstly, while at some level your system has to know how to 'free' the memory block, the underlying malloc/free (which new/delete/new[]/delete[] generally call) don't always remember exactly how much memory you ask for, it can get rounded up (for example, once you are above 4K it is often rounded up to the next 4K-sized block).
Therefore, even if could get the size of the memory block, that doesn't tell us how many values are in the new[]ed memory, as it can be smaller. Therefore, we do have to store an extra integer telling us how many values there are.
EXCEPT, if the type being constructed doesn't have a destructor, then delete[] doesn't have to do anything except free the memory block, and therefore doesn't have to store anything!
It is not standardized. In Microsoft's runtime the new operator uses malloc() and the delete operator uses free(). So, in this setting your question is equivalent to the following: How does free() know the size of the block?
There is some bookkeeping going on behind the scenes, i.e. in the C runtime.

Pointer pointing to an element in a vector gets set to NULL when the structure grows

A pointer to an object gets set to NULL, despite the fact that there is no pointerToObj = NULL anywhere in the function. Later I use that pointer for something and it causes an Access Violation exception. I also added a test pointer to see if it will preserve its value, but no - both get set to NULL at the same time.
The pointer points at an object in a vector. At one point, I add a new object to the vector, so the structure grows. Right after this the pointer gets set to NULL. I tested this - all pointers, that point to a certain element of the vector, get set to NULL right after I add the new object.
I suspect that this happens because of the way the Vectors work - if I am not mistaken, they are based on a Stack. When a stack has to lengthen itself, it must copy itself in a new bigger array and delete the old one. But now the new array is located elsewhere in the memory, so my pointer is no longer pointing in the correct location.
Is this really the case?
Yes, adding an element to a std::vector may invalidate pointers to its elements for the reason you describe (but it doesn't have anything to do with stacks). Your pointer isn't being magically set to null though, it just points at a non-existent object.
Using std::vector to store pointers or objects that have pointer members resets all the pointers to the new vector allocated memory addresses-NULL or any memory address.
You can set the pointer to the value you want after you push it back in the vector instead of setting it before push_back().
For Example, if you have an object called x of class client that has pointers, and you want to store it in vector v.
Do this:
client x;
v.push_back(x);
static int i = 0;
v[i++].set_name();
So, if you called v[i].get_name() the pointer will be pointing on the name.
Instead of:
client x;
x.set_name();
v.push_back(x);
x.get_name();
This will return a random memory address.
Be carful, every time you push_back() an element the vector size is doubled, and the first element pointer will point to a new location that fits the doubled size. You can set the first element to a garbage or empty object of type client, or you can reserve vector memory before you do anything with it in order to keep all the addresses as they are. You can see how this is done here: change of vectors first pointer.

C++ Deleting part of dynamic array

Say I have a dynamic array like:
int* integers = new int[100];
Is there a way to delete only part of the array such as:
int* integers2 = integers + 50;
delete[] integers2;
I want to not only delete everything 50 and beyond, but if I call another delete[] on the original integers array, then it would only delete the correct amount of memory and not try to delete the originally allocated amount and seg fault.
Why I want to do this: I have a data structure that is structured in levels of arrays, and I want to be able to create this data structure from a full array. So I want to be able to say
int* level1 = integers;
int* level2 = integers + 50;
int* level3 = integers + 100;
But when level 3 is no longer needed, the data structure will automatically delete[] level3. I need to know that this will behave correctly and not just destroy everything in the array. If it will then I need to just create new arrays and copy the contents over, but it would be nice to avoid doing that for performance reasons.
Edit: Everyone seems to be jumping to the conclusion that I just should use a dynamic resizing container (ie vector, deque) in the first place for my data structure. I am using levels of arrays for a good reason (and they aren't equally sized like I make it look like in my example). I was merely looking for a good way to have a constructor to my data structure that takes in an array or vector and not need to copy the original contents over into the new data structure.
No, this will not behave correctly. You can only delete[] pointers that you got from new[], else the results are undefined and bad things might happen.
If you really need the array to get smaller you have to allocate a new one and copy the contents manually.
Typically when memory gets allocated, there is some housekeeping stuff before the pointer.
i.e. houskeeping (pointer) data
You will mess that up.
int* integers2 = integers + 50;
delete[] integers2;
Will not work because new is created on int*, so space of 100 int has been assigned to integers, now integers2 is only a pointer to 50th location of integers, it has no space assigned to it of its own, so using delete will not delete rest of integers2, it'll only give erratic results.
What you can do is copy the first 50 in another array, and delete the previous array completely.
delete will only delete the pointer which has space assigned to it, using delete to another pointer pointing to the space assigned to first pointer will not delete any space assigned to the first pointer.
delete[] integers2 will not delete any space assigned to integers1 or any other pointer.
Dynamic allocators (like new) generally don't like you releasing part of the memory they gave you. If you use the <malloc.h> defined library functions malloc() and free() instead of new and delete, then you can use realloc(), though in most cases that you would care about the size difference it's just going to copy for you anyway.
Dynamically sizing containers generally use an exponential rule for resizing: if you run out of space, they (for example) double the allocation (and copy the old data over), if you remove data until you are using (for example) less than half the allocation they copy into a smaller allocation. This means you never waste more than half the memory, and the cost of copying per element added or removed is effectively constant. Implementing all of this is a pain in the ass, though, so just use std::vector and let it do it for you :).
No you can't do this with a fixed sized array allocated with new[]. If you want to have a dynamic array use one of the STL containers, such as std::vector.

adding element to an array

How can I add an element to an array where the size of the array is unknown and vectors are prohibited?
If the size of the array is unknown how do you know where to put the element and whether it will fit?
Anyway, if it won't fit you have to allocate a new array that is big enough.
If you allocated originally with malloc rather than new[] you can use realloc. You might be surprised to know that malloc / realloc are not "replaced" by new but are used for a different purpose, and in this case it is a useful thing to use. You can then insert objects into the allocated memory using placement new, and vector works this way. (allocator is used to actually allocate the memory but has an interface like malloc and although the implementation is up to the library author, they will almost certainly use malloc).
If you reallocated using realloc, you need to know that:
Any memory will be copied over. Beware though that if they are non-POD objects stored it is not safe to just do byte-by-byte copy
If realloc fails it returns NULL and your previous array is not freed. Be certain to keep a pointer to the old location until you know realloc worked.
If your array is not POD you cannot realloc, so malloc the new memory and use placement-new with a copy-constructor, then call the destructor on each object of the old memory before freeing it.
Placement new is used so you can allocate more memory than you need for now, i.e. more than you have objects for. This prevents you having to go through this process every single time you append.
I have explained how you might implement vector, but this is probably far too complex for you and probably for your tutor too. So just create an array with new[] and copy over the elements although it is horribly inefficient if you have to do this every time you add one.
You use lists for this purpose. An array is not supposed to be extended.
Your question does not make sense. If you can't use vector, means this is an assignment. I assume you have to use native arrays. If you don't know the size, you just cannot add an element to it. If you knew the size, you would have to allocate a bigger array, copy the contents of the old array plus the new element. Which the vector actually does for you :)
Without knowing the current size of the array and the capacity of the array (the distinction there is important), adding elements to the array is dangerous. You will never know when you have passed the bounds of the array (at least not before your program crashes from a buffer overrun error).
If your professor has banned vector for an assignment, chances are he wants to show you how to manage memory. He's looking for you to create an array using new and properly recognize when you need to allocate a new array of a larger size, copy the original elements, and deallocate the original array using delete.
One hint most professors fail to mention: when you allocate an array using new [], you must also deallocate it using delete [].