解除空指针引用并不总是未定义行为?

10
我一直知道标准规定对null解引用是未定义行为。然而,(链接1)称:“p = 0; *p;”不是固有错误,并提供了一个(链接2),该链接表示:“当p为空时,*p不是一个错误,除非将lvalue转换为rvalue”。(我认为这是个错别字,应该是“除非将lvalue转换为rvalue”)。链接1还说,char *p = 0; char *q = &*(p)是“未定义的”,我理解为至少是“明确定义的”或“实现定义的”。

能否请一位语言专家提供权威解释?

这是什么情况?


我不是语言法律专家,但我看过这些链接,认为在不使用值的情况下解引用空指针本身并不是UB。是的,它似乎有一个笔误,应该是左值到右值,因为在link1中引用的方式就是这样。我认为在静态成员的情况下这是有意义的,只需要operator*的静态类型,而link1在我看来也是一致的。 - drRobertz
如果实现导致了段错误,那真的算是未定义行为吗?我想不出有哪些实现不会导致段错误。 - Donnie
我对一个类实例指针解引用是未定义行为的类似问题很感兴趣。尝试将NUll指针分配给引用时,std::string &s = nullPointer; 尝试解引用char也应该意味着获取该位置的char值。解引用类实例意味着获取该位置的对象,但您实际上没有提取任何值,因为您没有使用成员访问运算符。我想知道这是否是未定义行为。请注意,解引用char*应该意味着获取该位置的CPU char。这应该会导致硬件异常。 - user13947194
1个回答

5
我通过这个答案深入探讨了关于空指针的间接寻址问题。简而言之,按照核心问题所解释的那样,它本身是明确的。委员会使用了多年前提出的一个空左值的概念(但从未采用);*p应该是这样的一个空左值,除非我们尝试访问这个左值背后的(不存在的)内存位置(例如通过执行左值到右值转换),否则所有其他操作都会像预期的那样工作。例如,&*p等同于p,除非p无效。 (这也适用于数组末尾后面的指针,这对于常见的习语&arr[n]是必要的)。
我还开始起草一份关于空左值的论文(这仍在进行中,并且对N4640的重新定义尚未完成),因此我们有机会在以后看到更多内容。

在我看来,如果C和C++的标准能够承认零大小的左值的概念,并将null视为这样的实体,那么许多问题都可以得到解决。如果我们认识到指针可以指向对象的起始点和/或结束点(例如对于int foo[10],指针foo+1将指向第一个元素的末尾和第二个元素的起始点,而foo+10只会指向第十个元素的末尾),并且指向不同对象的指针必须是不同的,除了指向一个对象起始点的指针可能指向另一个对象的末尾。 - supercat
如果采用“最后一个元素加一”的概念,就可以自然地与其他所有内容相匹配,而不需要特殊处理,空的左值也同样适用(起始地址可以等于另一个对象的结束地址,结束地址可以等于另一个对象的开始地址)。要求需要具有唯一地址的对象的代码必须给它们赋予非零大小,否则必须使用特殊手段创建唯一对象,这比要求所有对象都具有非零大小要干净得多。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接