// namespace scope
int *p1 = p1; // p1 0 initialized, `p1` is a null ptr, not UB?
Standard is ambiguous regarding this case, but "not UB" could reasonably be argued due to the static initialisation that precedes the dynamic initialisation. On the other hand standard implies that lifetime of the object hasn't started yet.
More details about the ambiguity here: If a global variable is initialized twice (statically, then dynamically), which initialization starts its lifetime?
// block scope
int *p2 = p2; // pointer to garbage location. has UB ?
Yes. Unlike in the case of static storage duration, the automatic object lacks the static initialisation stage, and has an indeterminate value before it is initialised. You're using that indeterminate value for the initialisation and the behaviour of the program is unambiguously undefined.
// block scope
int *p3 = p2; // Also has UB ?
Behaviour is already undefined in initialisation of p2
. But let's say p2
was an indeterminate value without previous UB:
int *p2;
int *p3 = p2;
The behaviour of this example is undefined as well.
Note that these have little to do with the object being a pointer. This applies to objects of nearly all types.
A reference must be initialised to refer to a valid object or function. Hence all three of these:
// namespace scope
int &r1 = r1; // r1 0 initialized, `r1` references 0, not UB?
// block scope
int &r2 = r2; // reference to intermediate value. has UB ?
int &r3 = r2; // Also has UB ?
make the program ill-formed.
I get a warning for a local variable, but not a global one.
I believe that the compiler is non-conforming in its failure to diagnose r1
. Clang does diagnose it, as required. Furthermore, clang's UB-sanitizer detects it at runtime.