5

My question:

int* x = new int;
cout << x<<"\n";
int* p;
cout << p <<"\n";
p = x;
delete p;
cout << p <<"\n";

I wrote this purely by myself to understand the pointer and to understand (also get lost in) the dynamic new and delete.

My XCode can compile the program and return the following results:

 0x100104250
 0x0
0x100104250

I know I can only call delete on dynamically allocated memory. However, I called delete on p in the above program and it compiles.

Could anyone explain this to me? Why could I delete p?

Moreover, I found if the program changes to the following:

 int* x = new int;
 int* p;
 cout << p <<"\n";
 delete p;
 cout << p <<"\n";

Then my Xcode again compiles and returns me:

 0x0
 0x0
 Program ended with exit code: 0

and now, I got completely lost:(. Could anyone please explain me this ? Why I could delete p since it has nothing to with x?


Since Xcode compiles successfully, I assume the above two programs are correct for computer. However, I think it is again the statement of "only call delete on dynamic allocated memory". Or probably, I didn't fully understand what is pointer and what is dynamic allocated memory. I found this post when I searched online. But I don't think it is like my case.

Please help me out.


I would like to ask one more question. The code is here about binary search tree. From line 28 to 32, it deals with deleting a node with one child. I put this part of code here, in case the weblink does not work.

else if(root->left == NULL) { struct Node *temp = root; root = root->right; delete temp; }

It is these codes leading me ask the above the question regarding pointer. Following the answer given by this post. Is it correct to understand the code in the following way?

I cannot firstly link the parent node of root to right child of root. and then delete the root node, as the subtree beneath the root node will also be deleted. So I must create a temp pointer, pointing to the memory slot, which is pointed to by root. Then I link the parent node of root to right child of root. and now, I can safely delete the memory slot pointed by "root", (i.e. temp as they both point to the same memory). In this way, I release the memory and also keep the link between parent and children. In addition, the temp is still there and still points to "that" memory slot. Should I set it to NULL after deletion?

Thank you all again in advance.

Yaofeng

Community
  • 1
  • 1
Bemtevi77
  • 155
  • 1
  • 7
  • 1
    You are "lucky" that `p` is `0` in your second code sample. Since it is uninitialized, it could have any value. As it is `0` (aka `NULL`) it is valid to call `delete` (this is helpful to avoid having a million checks for `NULL`, particularly when dealing with error conditions where an allocation failed, and you want to clean up the rest of the allocations - if all pointers are initialized to `NULL` first, then you can just `delete` everything, without worrying which one failed to allocate). – Mats Petersson Dec 08 '14 at 08:22
  • 1
    Just an advice, you always should initialize your pointer variables like int *p = 0; or int *p = NULL; That's because in a debug build this will be done for you. But in a release build it will not be done. This could save you a lot of time debugging. – user743414 Dec 08 '14 at 08:23
  • 1
    @user743414 Unless you're maintaining legacy code, you should be using C++11 and therefore `int *p = nullptr;`. (This part of) C++11 has been supported by all major compilers for years now. – Angew is no longer proud of SO Dec 08 '14 at 08:24
  • @Angew Ah ok. I didn't know that. :) Looks like I've learned something new. – user743414 Dec 08 '14 at 08:26
  • You may want to have a look at http://stackoverflow.com/a/6445794/1382251. Although it refers to the lifetime of a local variable, the concept is the same. – barak manos Dec 08 '14 at 08:37
  • Thank you for your suggestions of initializing with NULL. I would follow it even if the compiler does automatically. – Bemtevi77 Dec 08 '14 at 14:02
  • @barakmanos, I though I became clear after reading other's post. But now, it seems I'm still far away from fully understanding. I'll study more about pointer. Thank you very much. – Bemtevi77 Dec 08 '14 at 14:05

5 Answers5

2

Yes, you can only call delete on memory which was allocated via new. Notice that it's the address of the memory (the value of the pointer) which matters, and not the variable storing the pointer. So, your first code:

int* x = new int; //(A)
cout << x<<"\n";
int* p;
cout << p <<"\n";
p = x;  //(B)
delete p;  //(C)
cout << p <<"\n"; //(D)

Line (A) allocates memory dynamically at some address (0x100104250 in your example output) and stores this address in variable x. The memory is allocated via new, which means that delete must eventually be called on address 0x100104250.

Line (B) assigns the address 0x100104250 (value of pointer x) into the pointer p. Line (C) then calls delete p, which means "deallocate the memory pointed to by p." This means it calls delete on address 0x100104250, and all is well. The memory at address 0x100104250 was allocated via new, and so is not correctly allocated via delete. The fact that you used a different variable for storing the value plays no role.

Line (D) just prints out the value of the pointer. delete acts on the memory to which a pointer points, not on the pointer itself. The value of the pointer stays the same - it still points to the same memory, that memory is just no longer allocated.


The second example is different - you're calling delete p when p was not initialised to anything. It points to a random piece of memory, so calling delete on it is of course illegal (technically, it has "Undefined Behaviour", and will most likely crash).

It seems that in your particular example, you're running a debug build and your compiler is "helpfully" initialising local variables to 0 if you don't initialise them yourself. So it actually causes your second example to not crash, since calling delete on a null pointer is valid (and does nothing). But the program actually has a bug, since local variables are normally not initialised implicitly.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Thank you very much for your detailed and prompt answer. It made me feel much more comfortable about the pointer. – Bemtevi77 Dec 08 '14 at 14:22
1
p = x;

This would make p contain same value as x ( p would point to same object as x). So basically when you say

delete p;

Its doing delete on the address referred to by p which is same as that of x. Hence this is perfectly valid as object referred to by that address is allocated using new.

Second case :-

Co-incidently your pointer p is set by compiler as a NULL pointer( You should not depend on this). So deleting that pointer is safe. Had that not been a NULL pointer you would have possibly seen a crash.

ravi
  • 10,994
  • 1
  • 18
  • 36
  • Yes, it crashes sometimes. I found it when I was trying different codes. I forgot including it in my questions. Thanks a lot for confirming me this information. – Bemtevi77 Dec 08 '14 at 14:10
1

Ok, let's take a look at the documentation for the "delete" operator. According to http://en.cppreference.com/w/cpp/memory/new/operator_delete:

Called by delete-expressions to deallocate storage previously allocated for a single object. The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new(size_t) or operator new(size_t, std::nothrow_t).

So what happens is the following: you are calling the new operator, which allocates sizeof(int) bytes for an int variable in memory. That part in memory is referenced by your pointer x. Then you create another pointer, p, which points to the same memory address. When you call delete, the memory is released. Both p and x still point to the same memory address, except that the value at that location is now garbage. To make this easier to understand, I modified your code as follows:

#include <iostream>
using namespace std;

int main() {
    int * x = new int;               // Allocate sizeof(int) bytes, which x references to
    *x = 8;                          // Store an 8 at the newly created storage
    cout << x << " " << *x << "\n";  // Shows the memory address x points to and "8". (e.g. 0x21f6010 8)
    int * p;                         // Create a new pointer
    p = x;                           // p points to the same memory location as x
    cout << p << " " << *p << "\n";  // Shows the memory address p points to (the same as x) and "8".
    delete p;                        // Release the allocated memory
    cout <<  x << " " <<  p << " "
         << *x << " " << *p << "\n"; // p now points to the same memory address as before, except that it now contains garbage (e.g. 0x21f6010 0)
    return 0;
}

After running, I got the following results:

0x215c010 8
0x215c010 8
0x215c010 0x215c010 0 0

So remember, by using delete you release the memory, but the pointer still points to the same address. That's why it's usually a safe practice to also set the pointer to NULL afterwards. Hope this makes a bit more sense now :-)

Mihai Morariu
  • 166
  • 1
  • 7
0

Before the answers, you need to understand the following points.

  1. once you delete a pointer, it need not be assigned with 0. It can be anything.
  2. You can delete a 0 or NULL without any harm.
  3. Undefined behavior is one in which anything could happen. The program might crash, it might work properly as if nothing happened, it might produce some random results, etc.,

However, I called delete on p in the above program and it compiles.

Could anyone explain this to me? Why could I delete p?

That is because you assign the address of memory allocated by new via x. ( p = x;) x ( or p) is a valid memory location and can be deleted.

Now x is called a Dangling pointer. Because it is pointing to a memory that no longer valid. Accessing x after deleting is undefined behavior.

Could anyone please explain me this ? Why I could delete p since it has nothing to with x?

This is because your p is assigned with 0. Hence you are getting away with undefined behavior. However it is not guaranteed that your uninitialized pointer will have a value of 0 or NULL. At this point it seems to work fine, but you are wading through undefined behavior here.

Community
  • 1
  • 1
liaK
  • 11,422
  • 11
  • 48
  • 73
0

delete/free keyword is used to empty the stored value from the memory location. if we dont use pointers we have the reassign the value to NULL or just let them go out of scope.

Be careful using pointers, if we go out of scope using pointers without deleting the value. It will create memory leak. because that portion of the memory block is not usable anymore. And we lost the address because we are in different scope.

Dishank Jindal
  • 73
  • 1
  • 10