Home > Net >  C : Why will this not cause a dangling pointer?
C : Why will this not cause a dangling pointer?

Time:11-04

This is a dangling pointer

Foo* p;
{
  Foo f;
  p = &f;
}
// now p is dangling pointer

However, why is this not a dangling pointer?

Foo* p;
{
  Foo f;
  ...
  *p = f;
}
// p still contains the data of f

Is it because in the second case, we are doing a copy? Does this mean I should have written

*p = std::move(f);

if I do not want a copy?

Thank you!

CodePudding user response:

In your 2nd example p is uninitialized. Dereferencing an uninitialized pointer is Undefined Behavior.

CodePudding user response:

First, make the behaviour well-defined by giving p a valid value (not leaving things uninitialized is the simplest, cheapest form of bug prevention):

Foo* p = new Foo;
{
    ...

or

Foo x;
Foo* p = &x;
{
    ...

Now, in your first piece of code, p stores the location of f, which has been destroyed.
This is what makes it a dangling pointer.

In the second, you don't change p but store the value of f in *p, which is the same object as it always was.
Since that object still exists, the pointer is not dangling.

Compare these two snippets:

int x = 0;
int* p = &x;
{
    int y = 1;
    p = &y;
}
std::cout << "p: " << p << ", &x: " << &x;

and

int x = 0;
int* p = &x;
{
    int y = 1;
    *p = y;
}
std::cout << "p: " << p << ", &x: " << &x;

and you will see that the first prints two different addresses, and the second prints the same address twice.

CodePudding user response:

The distinction - if any - depends on your definition of "dangling pointer". And it is pretty academic.

Discussion of one possible definition. One possible definition of a dangling pointer is "a pointer that points to data which is no longer valid".

By that definition, your first example;

Foo* p;
{
  Foo f;
  p = &f;
}
// now p is dangling pointer

results in p being a dangling pointer, because it points at the object f, and f ceases to exist at the end of its enclosing scope (i.e. the }). Since p still exists, and its value is not changed in the process of f ceasing to exist, p now points at an object that no longer exists.

By that same definition, your second example;

Foo* p;
{
  Foo f;
  ...  
  *p = f;
}
// p still contains the data of f

does not produce a dangling pointer, since p never pointed at a valid object. In fact, p is uninitialised, so simply accessing its value produces undefined behaviour and its value (if any) is indeterminate. Dereferencing (i.e. evaluating *p) cannot be done without evaluating p so the expression *p and the statement *p = f both give undefined behaviour. Doing anything with *p after the } causes undefined behaviour (just as it does in your first example).

With this definition, The distinction of p being a dangling pointer in the first example and not in the second is a bit academic. The difference is that, in the first case, p is considered a dangling pointer because it no longer points at a valid object but, in the second case, p is not considered a dangling pointer because it never pointed at a valid object. Practically, the distinction makes no difference, since doing anything with *p gives undefined behaviour.

Discussion of a second possible definition A second possible definition of a dangling pointer is subtly different to the first "a pointer that points at invalid data".

By this second definition, both of your examples produce a dangling pointer. The first causes p to point at an object that no longer exists - so it points at invalid data. In the second example, p never pointed at a valid object - so it also points at invalid data. By this definition of a dangling pointer, p is a dangling pointer after the } in both examples because it now points at an invalid object.

The distinction under this second definition is still academic. Simply evaluating *p (let alone using it to change the invalid object p points at by, say, *p = some_Foo) gives undefined behaviour.

  • Related