取消引用空指针到什么时候会变成未定义的行为?

fre*_*low 8 c++ null object undefined-behavior dereference

如果我实际上没有访问解除引用的"对象",那么取消引用仍然未定义的空指针?

int* p = 0;
int& r = *p;    // undefined?
int* q = &*p;   // undefined?
Run Code Online (Sandbox Code Playgroud)

一个稍微更实际的例子:我可以取消引用空指针来区分重载吗?

void foo(Bar&);
void foo(Baz&);

foo(*(Bar*)0);  // undefined?
Run Code Online (Sandbox Code Playgroud)

好的,根据标准,参考示例肯定是未定义的行为:

在一个定义良好的程序中不能存在空引用,因为创建这样一个引用的唯一方法是将它绑定到通过解引用空指针获得的"对象",这会导致未定义的行为.

不幸的是,强调的部分是模棱两可的.它是导致未定义行为的绑定部分,还是取消引用部分足够?

Mat*_* M. 6

我认为每个C程序员应该知道的关于未定义行为的第二部分可能有助于说明这个问题.

以博客为例:

void contains_null_check(int *P) {
  int dead = *P;
  if (P == 0)
    return;
  *P = 4;
}
Run Code Online (Sandbox Code Playgroud)

可能优化为(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;
}
Run Code Online (Sandbox Code Playgroud)

哪个被优化为(DCE:死代码消除):

void contains_null_check_after_RNCE_and_DCE(int *P) {
  //int dead = *P; -- dead store
  //if (false)     -- unreachable branch
  //  return;
  *P = 4;
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,即使dead从未使用,简单的int dead = *P任务已经引起未定义行为在程序蠕变.

为了区分重载,我建议使用指针(可能为null),而不是人为地创建空引用并将自己暴露给未定义的行为.


Naw*_*waz 5

int& r = *p;    // undefined?
Run Code Online (Sandbox Code Playgroud)

我认为即使您实际上没有使用r(或*p) - 取消引用的对象,您也会有未定义的行为.因为在此步骤之后(即取消引用空指针),语言无法保证程序行为,因为程序可能会立即崩溃,这是UB的可能性之一.你似乎认为只有读书的价值r,从而被真正的目的调用UB.我不这么认为.

此外,语言规范明确指出"解除引用空指针的效果"会调用未定义的行为.它没有" 实际使用空指针中的解除引用对象的效果"调用UB.解除引用空指针(或者换句话说未定义的行为)的效果并不意味着您必然会立即遇到问题,或者在取消引用空指针后必须立即崩溃.不,它只是意味着,取消引用空指针后,未定义程序行为.也就是说,程序可以按照预期从开始到结束正常运行.或者它可能会立即崩溃,或者在一段时间后 - 几分钟,几小时或几天后崩溃.取消引用空指针后,任何时候都可能发生任何 事情.


Joh*_*itb 4

是的,这是未定义的行为,因为规范说“左值指定一个对象或函数”(第 3.10 条),并且对于 - 运算符来说*“[解除引用]的结果是一个左值,引用该对象或函数表达式点”(第 5.3.1 节)。

这意味着没有描述取消引用空指针时会发生什么。这只是未定义的行为。


归档时间:

查看次数:

1709 次

最近记录:

14 年,3 月 前