考虑下面的C ++代码:
int main() {
int* ptr; // Deliberately uninitialized
(void) *ptr; // Dereference, do not use result
}
此代码是否会导致未定义的行为?我假设答案是“是”,即使*ptr
的值实际上并未在任何地方使用。是否有规范的特定部分可以保证这一点?
(我很抱歉,如果这是重复的,但我似乎无法在网站上找到任何其他具体提出此问题的内容。)
答案 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将转换为目标类型的空指针值。