We can only de-reference a valid pointer and we can only check the address that a dangling built-in pointer points to. We cannot access its value (the value in the address of object it is pointing to).
int* ptr = nullptr;
if(ptr) // != 0x00000000
std::cout << *ptr << '\n';
ptr = new int(1000);
if(ptr) // != 0x00000000
std::cout << *ptr << '\n';
delete ptr; // still pointing at the address of that dynamic object but that object has been destroyed.
if(ptr) // succeeds or undefined behavior?
std::cout << *ptr << '\n'; // of course UB here
So it is clear for me but what matter me only is whether checking a pointer value is safe or yields UB? if(ptr)
. Because let's assume that I didn't access the value in that address like in std::cout << *ptr
.
CodePudding user response:
Is checking the value of a dangling pointer safe or Undefined Behavior?
It's not UB (since C 14), but "safe" depends on what you expect. There is no guarantee about the result of such check. It could be true or false. Assuming that a pointer is valid based on if(ptr)
is not safe in general.
CodePudding user response:
It is safe to dereference a non-null pointer only if it is actually pointing at a valid object, and unfortunately there is no way to test for that condition in C/C 1.
1: unless you manually keep track of the addresses of your valid objects and can thus search for the pointed-at address in your own tracking data.
It is not undefined behavior to test whether a pointer is equal to null or not. However, per [basic.stc.general]
, apparently after a block of memory is destroyed/reclaimed, any use of any pointer value referring to any part within that block is implementation-defined behavior:
When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values.
Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior.
Any other use of an invalid pointer value has implementation-defined behavior.
So, some people may argue that it means a pointer holding the address of a destroyed object MAY OR MAY NOT even be legal to compare against other pointers or even nullptr
itself, since the address is invalid. Only the compiler gets to decide if that is legal or not.
CodePudding user response:
Yes, for int* ptr;
, the expression ptr
is always safe. The behaviour of the program remains defined. But
- The specific value of a pointer is implementation-defined. [Ellipsis , emphasis mine]
[6.8.2.3.4] A value of a pointer type that is a pointer to or past the end of an object represents the address of the first byte in memory (6.7.1) occupied by the object or the first byte in memory after the end of the storage occupied by the object, respectively. [...] The value representation of pointer types is implementation-defined. Pointers to layout-compatible types shall have the same value representation and alignment requirements (6.7.6). [Note: Pointers to over-aligned types (6.7.6) have no special representation, but their range of valid values is restricted by the extended alignment requirement. — end note]
nullptr
is guaranteed to be equal(==
) to 0 andNULL
.- In boolean context,
nullptr
evaluates tofalse
, ALL other values, no matter whether they represent an address of valid objects, evaluate totrue
. delete
does not modify the pointer. EDIT: Or maybe it does, see the discussion in comments.- Pointers have same initialization rules as integers, meaning locals, non-static members are not initialized.
int* ptr; assert(ptr==nullptr);
does NOT hold in general. But global pointers are zero-initialized and thus evaluate to false at the start.
All taken together, although the program is safe, it is quite easy to make it nondeterministic at best.