I think the second opus of What every C programmer should know about Undefined Behavior might help illustrate this issue.
Taking the example of the blog:
void contains_null_check(int *P) {
int dead = *P;
if (P == 0)
return;
*P = 4;
}
Might be optimized to (RNCE: Redundant Null Check Elimintation):
void contains_null_check_after_RNCE(int *P) {
int dead = *P;
if (false) // P was dereferenced by this point, so it can't be null
return;
*P = 4;
}
Which is turn optimized into (DCE: Dead Code Elimination):
void contains_null_check_after_RNCE_and_DCE(int *P) {
//int dead = *P; -- dead store
//if (false) -- unreachable branch
// return;
*P = 4;
}
As you can see, even though dead
is never used, the simple int dead = *P
assignment has caused Undefined Behavior to creep in the program.
To distinguish between overloads, I’d suggest using a pointer (which might be null) rather than artificially creating a null reference and exposing yourself to Undefined Behavior.