如果我实际上没有访问解除引用的“对象”,那么取消引用空指针仍未定义?
int* p = 0;
int& r = *p; // undefined?
int* q = &*p; // undefined?
稍微更实际的例子:我可以取消引用空指针来区分重载吗?
void foo(Bar&);
void foo(Baz&);
foo(*(Bar*)0); // undefined?
好的,根据标准,参考示例肯定是未定义的行为:
空引用不能存在于定义良好的程序中,因为创建这样的引用的唯一方法是将它绑定到通过解除引用空指针获得的“对象”,导致未定义的行为
不幸的是,强调的部分含糊不清。是绑定部分导致未定义的行为,还是解除引用部分是否足够?
答案 0 :(得分:6)
我认为What every C programmer should know about Undefined Behavior的第二部作品可能有助于说明这个问题。
以博客为例:
void contains_null_check(int *P) {
int dead = *P;
if (P == 0)
return;
*P = 4;
}
可以优化为(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;
}
将其优化为(DCE:死代码消除):
void contains_null_check_after_RNCE_and_DCE(int *P) {
//int dead = *P; -- dead store
//if (false) -- unreachable branch
// return;
*P = 4;
}
正如您所看到的,即使dead
从未使用,简单的int dead = *P
赋值也会导致未定义的行为在程序中蔓延。
为区分重载,我建议使用指针(可能为null),而不是人为地创建空引用并将自己暴露给未定义的行为。
答案 1 :(得分:5)
int& r = *p; // undefined?
我认为即使你没有实际使用r
(或*p
) - 取消引用的对象,你也有未定义的行为。因为在此步骤之后(即解除引用空指针),语言无法保证程序行为,因为程序可能会立即崩溃,这是UB的可能性之一。您似乎认为只读取r
的值以便在真实目的中使用会调用UB。我不这么认为。
此外,语言规范明确指出“取消引用空指针的效果”会调用未定义的行为。它不说“实际使用空指针中的解除引用对象的效果”调用UB。取消引用空指针(或者换句话说未定义的行为)的效果并不意味着您必然会立即遇到问题,或者它必须立即崩溃取消引用空指针后。不。它只是意味着,在取消引用空指针后,程序行为未定义为。也就是说,程序可能从开始到结束正常运行。或者它可能会立即崩溃,或者在一段时间后 - 几分钟,几小时或几天后崩溃。在取消引用空指针之后,任何事情都可能发生 。
答案 2 :(得分:4)
是的,它是未定义的行为,因为规范说“左值指定一个对象或函数”(在第3.10节)并且它表示*
- 运算符“[取消引用]的结果是一个左值引用表达式指向的对象或函数“(在第5.3.1条)。
这意味着没有描述取消引用空指针时会发生什么。这只是未定义的行为。