0

Given this little piece of code :

#include <iostream>
#include <assert.h>
using namespace std;


struct Foo
{
    // something
};


int main()
{

    Foo *p1 = new Foo;
    Foo * p2 = p1;
    assert(NULL != p1);
    delete p1;
    p1 = NULL;

    assert(NULL != p2);
    delete p2;

    cout << "everything is cool!" << endl;

    return 0;
}

When I delete p1 , the second assert (assert(NULL != p2);) is not failing , why ?

The output : everything is cool!

Then why the assert of p2 is not failing ?

JAN
  • 21,236
  • 66
  • 181
  • 318

4 Answers4

4

When I delete p1 , the second assert (assert(NULL != p2);) is not failing , why ?

Deleting p1 or assigning to it has no effect on p2 itself. After you delete p1, p2 still points to that address, i.e. to a defunct object. It becomes a so-called dangling pointer. Of course, accessing it or deleting it (which you're doing) is undefined behavior.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
2
  1. Watch the stars, in particular.

    int i;
    
    int *p1 = &i;
    assert(p1 != NULL);
    
    int *p2 = p1;
    assert(p2 != NULL);
    
    *p1 = 10;
    assert(i == 10);
    assert(*p2 == 10);
    
    p1 = NULL; // does not affect the object p1 was pointing at
    
    assert(i == 10);
    assert(*p2 == 10);
    assert(p2 != NULL); // (which we already know, if the previous assert didn't crash)
    
  2. You're right to suspect that everything is not cool. The program invokes the delete operator twice on the same object (a "double free" error), which will tend to corrupt the heap. If the program continued, you would see undefined behavior at some point. Having undefined behavior rather defeats the point of writing a computer program. If you want to see errors like this immediately and unambiguously, run it under valgrind's memcheck or equivalent.

Community
  • 1
  • 1
sourcejedi
  • 3,051
  • 2
  • 24
  • 42
1

One of the biggest and most confusing-to-beginners misnomer in C++ is the term "deleting a pointer". This has undoubtedly originated from the fact that a delete expression takes a pointer as its argument:

T * p = new T;  // #1
delete p;       // #2

However, what's really going on is that line #1 creates a new, dynamic, unnamed object. Think about this again: There is no variable whose value is the object create in line #1. The object is really out of reach, as indeed it does not live in any scope. All we have is a pointer to it.

To end the lifetime of a dynamic variable, we have to use a delete expression. But since we already know that we can only ever really have a pointer the object, not the object itself*, the expression con­veni­ent­ly accepts a pointer to the object we're deleting.

So really we should say that in line #2 "we are deleting the object *p by giving a pointer to it to the delete expression" (namely &*p == p).

The pointer itself is entirely unaffected by the delete call.

*) Yes, we could also have a reference variable, like T & r = *new T;, but that would be insane.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

delete p; doesn't affect p. It destroys the object that p points to and frees its memory. p still has the value that it had before.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165