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.
