是否在C ++中取消引用无效指针但未使用结果的未定义行为?

时间:2016-02-29 22:48:35

标签: c++ pointers language-lawyer

考虑下面的C ++代码:

int main() {
    int* ptr; // Deliberately uninitialized
    (void) *ptr;     // Dereference, do not use result
}

此代码是否会导致未定义的行为?我假设答案是“是”,即使*ptr的值实际上并未在任何地方使用。是否有规范的特定部分可以保证这一点?

(我很抱歉,如果这是重复的,但我似乎无法在网站上找到任何其他具体提出此问题的内容。)

4 个答案:

答案 0 :(得分:7)

简单地取消引用尚未分配或标记为只读的指针可能会导致CPUs内存管理单元中出现硬件异常。因此,即使您不使用通过取消引用包含随机值的指针返回的任何垃圾值,也无法保证CPU将从此类事件返回。

但是,根据ISO C++11 Standard,声明未初始化的指针必须具有奇异值。因此,未初始化指针的值不是 undefined ,因为它不是垃圾。

然而,标准规定,对这种奇异值指针的大多数操作都是未定义的,除了用非奇异值覆盖奇异值

  

24.2.1 一般 [ iterator.requirements.general ]

     

5 [ 示例:在声明未初始化的指针x之后(与int * x;一样),x必须始终假设具有指针的奇异值。 - 结束示例] 对于奇异值,大多数表达式的结果未定义;唯一的例外是破坏一个包含奇异值的迭代器,一个非奇异值赋值给一个包含奇异值的迭代器,对于满足DefaultConstructible要求的迭代器,使用一个值初始化的迭代器作为源复制或移动操作。 [ 注意:默认初始化不提供此保证,但区别仅适用于具有普通默认构造函数的类型,例如指针或包含指针的聚合。 - 结尾注释 ] 在这些情况下,奇异值会以与任何其他值相同的方式被覆盖。可解除引用的值总是非单数的。

答案 1 :(得分:1)

您正在读取未初始化变量(指针)的值。这是未定义的行为。

有趣的是,因为*ptr是一个废弃的值表达式,所以它不会经历左值转换为右值。因此,如果*ptr未初始化,那将是安全的。

答案 2 :(得分:-1)

根据标准,解除引用非初始化指针是未定义的行为。但是,在现实生活中很少出现这种情况:编译器很聪明,可以删除这样的代码,因为它实际上并没有在任何地方使用过。所以,即使解引用指针是未定义的行为,如果你不使用结果很可能你实际上没有引用它。我用clang ++测试了你的代码,并且生成了NO CODE。

来自标准(4.1):

  

可以转换非功能非数组类型T的左值(3.10)   到一个右值。如果T是不完整类型,则需要一个程序   这种转变是不正确的。如果对象是左值   refer不是T类型的对象,也不是类型的对象   从T派生,或者如果对象未初始化,则为程序   需要这种转换具有未定义的行为。如果T是   非类型,rvalue的类型是cv-nonqualified版本   除此之外,右值的类型是T.

答案 3 :(得分:-2)

根据标准,这不是未定义的行为。

以下是the open-std review page的官方讨论和解释。

  

我们同意标准中的方法似乎没问题:p = 0; * P;本质上不是一个错误。左值到右值的转换会给它带来不确定的行为。

此外,在标准[第4.10.2节]中,它说:

  

类型为“指向cv T的指针”的prvalue,其中T是对象类型,可以转换为类型为“指针”的prvalue   cv void“。将指针的非空指针值转换为对象类型的结果为“指针指向   cv void“表示内存中与原始指针值相同的字节的地址。空指针   value将转换为目标类型的空指针值。