Lets say I allocate an array of ints
int test[] = new int[100];
I take a pointer to somewhere in the middle
int *temp = &test[50];
Then I call delete[] on the temp
delete[] temp
How will the compiler know the size of elements to delete in this case?
It won't (or will, I don't know). You're invoking undefined behavior. You're only allowed to call delete[] on a pointer allocated with new[].
For example, I get a crash in MSVS.
You have to pass the same memory location which was returned by new[], passing anything else is undefined behavior.
You cannot do that. A compiler has to keep track of the size of memory that it allocates. The standard does not say how it must to this. Some compilers store the size of the allocated memory just before the returned address. In such cases what you're doing can lead to undefined behavior.
The answer is no.
Because delete operator need to locate the location of the memory block and it's size, which is mostly ahead the first member of the allocated array.
you should have a look at the "Inside c++ object model"
Related
Let's say you have a function
int * something ( int size ){
int * sample= new int[size];
//... do something
return sample;
}
Then if using it somewhere else like
...
Int * temp=something(5);
// use the array....
delete [] temp;
....
Is this gonna cause mem leak??
It is legal but quite error-prone because there's risk of memory leak if there's an exception between the array being allocated and the same array being deallocated. Better use smart pointers to make this code exception-safe.
Yes, you can delete[] what was new[]ed earlier as long as you use the same type pointer and as long as the pointer still points onto the same address and the array was not yet deallocated elsewhere in your code (so-called "double free" problem). All three requirements must be met, otherwise you run into undefined behavior and then all bets are off.
This question was asked as part of Does delete[] deallocate memory in one shot after invoking destructors? but moved out as a separate question.
It seems (Correct me if wrong) that the only difference between delete and delete[] is that delete[] will get the array size information and invoke destructors on all of them, while delete will destruct the only first one. In particular, delete also has access to the info on how much total memory is allocated by new[].
If one doesn't care about destructing the dynamically allocated array elements, and only care that the memory allocated either by new or new[] be deallocated, delete seems to be able to do the same job.
This How does delete[] "know" the size of the operand array? question's accepted answer has one comment from #AnT and I quote
Also note that the array element counter is only needed for types with non-trivial destructor. For types with trivial destructor the counter is not stored by new[] and, of course, not retrieved by delete[]
This comment suggests that in general delete expression knows the amount of the entire memory allocated and therefore knows how much memory to deallocate in one shot in the end, even if the memory hold an array of elements. So if one writes
auto pi = new int[10];
...
delete pi;
Even though the standard deems this as UB, on most implementations, this should not leak memory (albeit it is not portable), right?
Under the C++ standard, calling delete on something allocated with new[] is simply undefined behavior, as is calling delete[] on something allocated with new.
In practice, new[] will allocate the memory through something like malloc as will new. delete will destroy the pointed-to object, then send the memory to something like free. delete[] will destroy all of the objects in the array, then send the memory to something like free. Some extra memory may be allocated by new[] to pass to delete[] to give delete[] the number of elements to be destroyed, or not.
If actual malloc/free is used, then some implementations will allow a pointer to anywhere in the malloc'd block to be used. Others won't. The exact same value is required to be passed to free as you got from malloc for this to be defined. There is an issue here in that if new[] malloced some extra room for the array size/element stride and stuck it before the block, then delete is passed the pointer-to-the-first element, then delete will pass free a different pointer than new[] got from malloc. (I think there is an architecture where something like this happens.)
Like most undefined behavior, you can no longer rely on auditing the code you write, but instead you are now committed to auditing both the produced assembly, and the C/C++ standard libraries you interact with, before you can determine if the behavior you want to do is correct. In practice, that is a burden that will not be fulfilled, so your code ends up having negative value, even if you check that things work the way you expect the one time you actually checked. How will you ensure that an identical check (of the resulting binary and its behavior) will occur every time the compiler version, standard library version, OS version, system libraries, or compiler is changed?
This is correct. Difference between delete and delete[] is that the latter knows the number of items allocated in the array and calls destructor on every object on them. To be 100% correct, both actually 'know' it - the number of items allocated for an array is equal to the allocated memory size (which both know) divided by the size of the object.
One might ask, why do we need delete[] and delete than - why can't delete perform the same calculations? The answer is polymorphism. The size of the allocated memory will not be equal to the sizeof static objec when deletion is done through the pointer to the base class.
On the other hand, delete[] does not take into account a possibility of object being polymorphed, and this is why dynamic arrays should never be treated as polymorphic objects (i.e. allocated and stored as a pointer to the base class).
As for leaking memory, delete will not leak memory in case of POD types when used on arrays.
A concrete reason to avoid all constructs provoking undefined behavior, even if you cannot see how they could possibly go wrong, is that the compiler is entitled to assume that undefined behavior never happens. For instance, given this program...
#include <iostream>
#include <cstring>
int main(int argc, char **argv)
{
if (argc > 0) {
size_t *x = new size_t[argc];
for (int i = 0; i < argc; i++)
x[i] = std::strlen(argv[i]);
std::cout << x[0] << '\n';
delete x;
}
return 0;
}
... the compiler might emit the same machine code as it would for ...
int main(void) { return 0; }
... because the undefined behavior on the argc > 0 control path means the compiler may assume that path is never taken.
This looks simple question but my friend debated with me that below program invokes UB. But I think he is incorrect.
Consider following program:
#include <iostream>
int main()
{
int* p=new int[3]();
int* q=p;
for(int i=0;i<3;i++)
std::cout<<q[i]<<' ';
delete[] q;
std::cout<<'\n';
}
Is this program's behavior well defined? What happen if I write delete[] p; instead of delete[] q; ? Is it valid?
Yes the program is well defined. First you create a pointer assigned to newly allocated memory.
int* p=new int[3]();
Then you create another pointer pointing to that memory
int* q=p;
You then use that pointer to assign data into that memory. After that you delete memory which is pointer to q which is the same as p which is okay. The program returns and all is well
delete doesn't care about what variable you use. What is important is that the memory that the pointer points to was created with new and that you only call delete once on the memory.
The pointer returned by the new[] operator is not the start of the allocated memory but rather points to the first object (or the object at index 0). Now, based on the compiler you're using, the run-time system stores the number of objects, n, somewhere where it can be retrieved if you only know the memory location pointed by p.
According to this blog, the deletion of a vector performs this operation in reverse:
When you do "delete[] p", you are saying, "p points to a bunch of
objects, but I'm not telling you how many." In this case, the compiler
needs to generate extra code to keep track of how many it needs to
destruct. This extra information is kept in a "secret place" when the
vector is allocated with "new[]".
Since doing int *q = p essentially points to the same array's 0th object, it is equivalent to call delete[] q and delete[] p.
Operator delete can be applied ONLY to memory (i.e. address) that was allocated with operator new. If you allocate once you should free (detele) also once, does not metter which pointer (variable storing address) is used, so your code is valid.
But, remember, after you delete[] q neither q nor p DO NOT have to be used. The best way is assigne NULL to both pointers.
No UB. It will work fine. Not much to add here.
I have the following C++ code:
int main(){
unsigned char *abc = (unsigned char *)calloc(100,1);
unsigned char *def = &abc[50];
delete def;
}
Would this deallocate all the memory allocated by the call to calloc, or just the memory starting at the memory location where def points to?
It is undefined behavior. A crash, if you are lucky.
According to C++ standard (Working Draft, N3291=11-0061)
3.7.4.2 Deallocation functions [basic.stc.dynamic.deallocation]
...
The value of the
first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation
function is one supplied in the standard library, the call has no effect. Otherwise, the behavior is undefined
if the value supplied to operator delete(void*) in the standard library is not one of the values returned
by a previous invocation of either operator new(std::size_t) or operator new(std::size_t, constvstd::nothrow_t&) in the standard library ...
There are several problems here. First, you should use free if you used calloc.
Then, you should pass to free the same pointer you got from calloc.
calloc allocates memory as one continuous block, and the entire block gets deallocated with free, not a part of it.
See http://www.cplusplus.com/reference/cstdlib/calloc/.
delete can only delete memory allocated with new.
for memory allocated with calloc deallocate it using free.
and no, you can't just use a pointer to somewhere inside the allocated memory.
in C++, deal with simple character strings by using std::string from the <string> header.
it takes care of memory management for you.
It wouldn't necessarily deallocate anything as it has undefined behavior. You can only call delete on a pointer which was allocated with new. Not only was the memory allocated with calloc instead of new, but you are also not passing a pointer to what calloc returned, but to some other position within that block of memory.
Isn't *abc undefined there? delete def; wouldn't do anything if there is nothing to delete!
int* func()
{
int* i=new int[1];
//do something
return i;
}
void funcc()
{
int* tmp=func();
//delete allocated memory after use
delete tmp;
}
should delete working as described in the second function be a correct use ?
I think I didn't allocate memory to it by new ? new was used in the first, to be sure.
It should be delete [] tmp; because you're doing array new, but otherwise, it's correct.
As others have stated, you should use delete[] to delete arrays, not delete.
But, if you're asking whether it's okay to delete tmp because the memory it points to wasn't allocated with new, then your premise is incorrect.
It was allocated with new. The address of the memory that you allocate within the function for i is passed back to be stored in tmp, so it does point to memory that was allocated by new.
You're correct that i itself is out of scope at that point but memory allocated by new survives the scope change on exit from the function. And, since you're storing its location into tmp, you still have access to it.
Hence the deletion (once you make it an array deletion with []) is quite valid.
This is Undefined Behaviourâ„¢. You can only use delete if you used new. If you used new[], you MUST delete[] it. More than that, this is hideously unsafe code- you need a smart pointer.
No. new T[] should match delete []t. And new T should match delete t. Otherwise, your code would invoke undefined bevavior.
And it doesn't matter if you do delete []tmp outside the function. Its okay to do so. All that you need to keep in mind that the form of delete.
My spidey-senses tell me that you're wondering whether the dynamically-allocated int that you create in func is the same one that you attempt to delete in funcc.
The answer is: yes. Although you don't use strictly the same pointer variable, both pointers point to the same object.
However, please remember to use delete[] (with the []) when you used new[] (with the []). Your code is broken until you fix this.
Also, try to avoid newing in one place and deleteing in another. Perhaps consider a std::vector instead, which is far less error-prone.