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.
Related
I wanted to ask, is dynamically creating a pointer, and then changing a pointer address to something else still deleting the original allocated space?
for example:
int main()
{
int c = 50;
// Memory leak
int * q = new int;
q = & c;
delete q;
}
What exactly is getting deleted or happening?
Thanks!
What exactly is getting deleted or happening?
Memory leaking and undefined behaviour.
When you do q = & c; you are losing your only tracking of the memory allocated by new int. Noone keeps track of this for you, there is no garbage collector, it is simply lost and cannot be recovered.
When you then do delete q; (where q is assigned to &c) you are deleting memory that you didn't allocate, and worse you are deleting memory on the stack. Either of these will result in undefined behavior.
This is an excellent preface into why you should avoid using pointers in circumstances where you don't need them. In this case, there is no reason dynamically allocate your int. If you really need a pointer, use a c++11 smart pointer (or boost if you don't have c++11). There are increasingly rare cases where you really do need a raw c type pointer. You should read Effective Modern c++ Chapter 4 for excellent detail on this subject.
is dynamically creating a pointer, and then changing a pointer address to something else still deleting the original allocated space?
No. delete will deallocate the memory to which its operand points. You must delete the same block of memory that you obtained from new.
int c = 50;
int * q = new int;
int * r = q;
q = & c;
delete q; // WRONG! q points to something you didn't get from new
delete r; // OK! p points to the block you got from new
To be even more clear, delete doesn't care about what variable it operates on, it only cares about what that variable points to. In the last line above, r points to the block that was originally pointed to by q and allocated by new, so you can safely delete it. q points to statically allocated memory, not something you got from new, so you can't delete it.
Instead of changing where q points, though, you can copy the value you want into the space that q points to:
int c = 50;
int * q = new int;
*q = c;
delete q; // OK! q still points to the same place
Here you're changing the value stored in the location to which q points, but you're not changing q itself. q still points to the block you got from new, so it's safe to delete it.
You code will (try to) delete c. There's no memory management or anything like that in C/C++. delete will try to delete whatever the given pointer points to, and and whatever is not deleted (either by calling delete for variables created with a call to new, or by leaving the scope for local variables) will remain in memory until the program ends.
Notice that trying to delete a local variable will propably cause a crash, since delete actually checks (in a very basic manner) what it deletes - at least to know how much memory has actually been allocated at that address. And at this check, it will propably notice that c doesn't include this information, or that it isn't even at the right end of the memory space, so it will crash.
It will crash because c is created in the stack memory section. If you're lucky and the program didn't crash you aren still leaking memory because the q reference is lost.
First answer is to your question:-
I wanted to ask, is dynamically creating a pointer
We don't create a pointer dynamically. Pointers are just a variable like other variable in C and C++. Difference is, pointer is a variable which can store the address of a particular memory location. In run time you just dynamically allocate memory and assign the address of first address location of that memory size into it.
Now what will happen if you don't delete/free the memory and assign a new address to it. In that case memory will not be release/freed and that can not be use anymore as that will never be marked as free by OS. When you free/delete memory O/S mark that area as free to use, and your running process can utilize it in future. That is call proper memory management. Improper memory manage leads your program to memory leak.
The following code compiles but runs with mistake:
int main() {
int (*d)[2] = new int[3][2];
// do something
delete [] *d; // this is wrong
delete [] *(d+1); // this is also wrong
//delete [] d; // this works
return 0;
}
I do not know why "delete [] *d" does not work because *d seems to be a pointer to a chunk containing 2 integers and delete[] should destroy that chunk.
Furthermore, I am not sure whether "delete [] d" is enough to release all six elements since two-dimension array is involved here.
Thanks!
The memory you allocated is allocated as one continuous block (or chunk) of memory that stores an array obejct of int[3][2] type. It should be freed as one block
delete [] d;
That's all you need to do.
Freeing just some partial sub-block of a whole block is not supported by C++ dynamic memory management mechanisms.
Your delete [] *d is indeed wrong - the behavior is undefined. However, it has a good chance of "working" in practice since int (*)[2] pointer d and [decayed] int * pointer *d point to the same spot in memory, and the underlying types are trivial. If it "works", it should typically have the same effect as delete [] d;, i.e. free the entire 2D array.
int[3][2] is not a pointer of pointers but just a multi-dimensional array, allocated as a single pointer.
You cannot delete "lines" of it because there are no lines. Memory is contiguous.
I have some issues about this code:
1) Why the output returns trash if I delete the first cell ?
int b = 1025;
char *v = new char[sizeof(int)];
memcpy(v,&b,sizeof(int));
char *pp = (char*)v;
++pp;
delete v; // is equal delete &v[0]
cout<<"salida"<<*pp;
2) How to delete dynamically allocated memory when i have void* ...
void *pv = v;
is correct
delete pv;
or
delete [](char*) pv;
i think what you are trying to do is deallocating the dynamically allocated memory..
first a pointer is always size of an int.
It only handles data locations(references).
A char pointer can store the address of a char type variable.
A void pointer can store the address of any data type.
so delete option works for both type of data types.
it simply deallocate the space and make it available on heap
A call to new[] needs to be matched by a call to delete[] on the same memory address and using the same pointer type.
A call to new needs to be matched by a call to delete on the same memory address and using the same pointer type.
If you mix things up, then you're invoking undefined behavior and will eventually have problems.
Maybe you'll occasionally be "lucky" and get away with it in certain simple circumstances because of how certain compilers have implemented dynamically allocated memory, but it's still a bad idea and could break at any time. If you try this with a class type which has a destructor, then one common consequence is that the destructor will not be properly run on some or all of the instances. But of course there are other possibilities, such as heap corruption.
So the result of a new char[] statement must be deallocated by a delete[] statement on a pointer of type char*.
You can't delete just one element of a dynamically-allocated array. If you allocate an array with new[], you can only delete the entire array, and you must use delete[], not delete.
Doing
char *v = new char[sizeof(int)];
and then
delete v;
invokes undefined behavior. You need to do delete[] v, and then you can no longer use pp because it points to something that's been deleted.
What exactly are you trying to delete, the char *v or void *pv?
If you want to delete char *v,
delete[] v;
v = NULL; // v still exists, but it's a dangling pointer now, so we set it to NULL (or 0)
Usually when you want to delete something, it has to be paired with new. So I think if you want to delete void *pv, you have to initialize the void pointer to new like this:
void** pv = new(void*); // Create a void pointer using new
pv = (char *)v;
delete pv;
If I've already used new to allocate memory to int* p, but then if I want use new again, will the previously allocated memory remain valid?
int *p;
p= new int[5]; //is this going to remain valid after the following statement?
p= new int[10];
If yes, then am I required to delete[] it? I tried doing that but the compiler says that the pointer is valid, so I can't delete it. Is there any other way to get rid of the previously allocated memory?
The second use of new[] is, in itself, completely independent of the first. The second use of new[] does not in any way invalidate the first block of memory that you allocated.
When you allocate memory, you are asking the system to allocate memory, and tell you the address of the memory that it, the system, allocated. It is your responsibility to remember that address so that you can refer to it in the future. You need to be able to refer to the memory in order to access it and eventually deallocate it.
This is your code:
int *p;
p= new int[5];
p= new int[10];
The first assignment records the address of the first allocated block. The second assignment overwrites that value with the address of the second block.
So, the problem you have is that you no longer have a variable that contains the address of the first block of memory. Whilst that first block is still valid, you are unable to refer to it. In particular, since you can no longer refer to it, you cannot deallocate it and so it will be leaked.
If you wish to be able to deallocate both blocks of memory, then you have to be able to refer to both blocks. Which means that you must have two variables to hold the two distinct addresses.
int* p1 = new int[5];
int* p2 = new int[10];
Now you can refer to blocks blocks separately. When you are done, deallocate the memory:
delete[] p1;
delete[] p2;
On the other hand, if you want to delete the memory before allocating a new block, you can do that:
int* p = new int[5];
// use p
detete[] p;
int* p = new int[10];
// use p
delete[] p;
The prev remain somewhere on the heap. You can use valgrind to verify that. If you want to use the sane pointer again and again you might consider to create a function that delete the last allocation and allicate new space each time...
To add to what David Heffernan said, when you have this statement:
int *p;
p= new int[5];
don't think of p as being assigned to the memory that was allocated. The memory exists independently of p, but you're using p as a sort of post-it note to jot down where that memory is located. When you assign a new value to p, you're simply overwriting your note. You haven't done anything to the memory that was allocated-- you just don't know where it is anymore.
If the memory you previously allocated is not needed anymore, you have to use delete [] to free the memory. Otherwise, the memory is still out there, but you have no way to access it any more, thus a memory leak.
You will need to delete[] p; in order to avoid memory leak. The memory doesn't get released by itself. What's the exact information the compiler is giving in terms of "can't delete it"?
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.