引用未初始化的内存而不访问它是不是合法?

Posted

技术标签:

【中文标题】引用未初始化的内存而不访问它是不是合法?【英文标题】:Is it legal to reference uninitialized memory without accessing it?引用未初始化的内存而不访问它是否合法? 【发布时间】:2013-08-05 15:01:37 【问题描述】:

以下情况,我有一个包含指向整数变量的指针的结构,如下所示:

struct Structure[] =  
     &Var[0], &Var[1] ,
     &Var[2], &Var[3] 
;

事情是:Var 在第一次填充此结构时未初始化。 (如:NULL) 不久之后(第一次传递)变量Var 将被初始化,并且引用将相应更新。

我认为这没有任何故障的原因,但我希望您能在这方面提供专业知识。 将无效内存(带有数组下标)的引用放入这样的数组中是否合法?还是我需要针对这种情况采取不同的方法?

在第一次初始化之前,我不会访问这些变量的内容。

非常感谢。

编辑: 为了以后读者的利益:Var是一个全局指针变量,一开始就被初始化为NULL。初始化通过使用new将其变成一个数组。

【问题讨论】:

我有理由确定答案是否定的,并且某些优化器会破坏您的代码。 “或者我需要一种不同的方法来应对这种情况?”嗯,也许,初始化变量? Var 是引用还是指针? 什么是未初始化的,VarVar[0]?如果Var 被初始化为指向“一个未初始化的内存区域”,那么你的代码就可以了。 如果Var 是一个未初始化的指针,那么这就是各个方向的UB。如果它是 T 类型的 array 且具有未初始化的 content 则这是定义的行为,只要您不 read 的内容存储在您的结构(或Var)中的地址,直到上述位置它们自己的存储已被初始化。如果没有更多关于 Var 类型的信息,那就是我能提供的最深的评论了。 【参考方案1】:

我假设Var 是一个指针对象并且它的当前值是一个空指针。您的陈述暗示了这一点:

Var 在第一次填充此结构时未初始化。 (如:NULL

我还假设Var 没有在块范围内定义。如果它是在块范围内定义的,并且您没有对其进行初始化或为其分配值,那么它的值就是垃圾,不一定是空指针值,并且任何引用其值的尝试都有未定义的行为。

行为未定义。

如果Var == NULL,则&Var[N] 具有未定义的行为。

arr[index] 根据定义等同于*(arr + index),因此&Var[N] 等同于&(*(Var + N))。指针算术的行为是根据指针指向的数组对象的元素来定义的(单个对象被视为单元素数组),而空指针不指向任何东西。

题外话:

C 明确表示&*x 被评估为x&[x[i]) 被评估为x+i; C++ 没有这样说,所以& 的操作数必须是有效的。 C++ 有一个添加0 的特殊情况,即使对于空指针也有很好的定义(C 没有这种特殊情况)。但是&Var[0] 在 C 和 C++ 中仍然无效,但原因不同。在 C 中,它等价于 Var + 0,但将 0 添加到空指针具有未定义的行为。在 C++ 中,它 等同于Var + 0;而是相当于&(*(Var + 0))Var + 0 是一个空指针,取消引用它有未定义的行为。)

题外话结束。

是的,只是计算一个无效地址具有未定义的行为,即使它从未被取消引用。

这是 2011 ISO C++ 标准 5.7 [expr.add] 第 5 段中的相关文本;特别注意最后:

当具有整数类型的表达式被添加或减去时 从一个指针,结果具有指针操作数的类型。如果 指针操作数指向数组对象的一个​​元素,而数组 足够大,结果指向一个元素偏移量 原始元素使得下标的差异 结果和原始数组元素等于积分表达式。 换句话说,如果表达式 P 指向一个 数组对象,表达式 (P)+N(等价于 N+(P))和 (P)-N (其中 N 的值为 n)分别指向 i + n-th 和 i − 数组对象的第 n 个元素,前提是它们存在。此外,如果 表达式 P 指向数组对象的最后一个元素, 表达式 (P)+1 指向数组对象的最后一个元素, 如果表达式 Q 指向数组的最后一个元素 对象,表达式 (Q)-1 指向数组的最后一个元素 目的。如果指针操作数和结果都指向元素 相同的数组对象,或数组的最后一个元素 对象,评估不应产生溢出;否则, 行为未定义。

【讨论】:

您能否提供禁止对空指针进行算术运算的参考?还是我误解了你的意思? @MarkB 这与NULL的法律定义有关。如果NULL 定义为((void*)0)(在C 中合法,在C++ 中非法),那么对其进行任何算术都是非法的。 (显然,如果 NULL 被定义为 0,那么 NULL + 0 是合法的。) 另外,NULL + 1 在 C++ 中应该没问题。但是,尝试使用结果来初始化指针是行不通的,因为0 + 1 可能是一个整数常量表达式,但它肯定不会计算为 0。 "(C 明确表示 &*x 被计算为 x,而 &[x[i]) 被计算为 x+i;C++ 没有这样说,所以 & 的操作数有是有效的。)”似乎这意味着当Var是空指针时,即使&Var[0]在C++中也无效。 @ATaylor:为了未来读者的利益,请使用该信息更新您的问题。【参考方案2】:

由于在第一次传递之后才使用这些值,因此请做正确的事情并将结构的指针初始化为 null。然后在你知道它们的时候输入正确的值。如果您采用这种方法,您的“是否合法”问题就会消失!

【讨论】:

+1。其实struct Structure[2]; 就够了。如果从未使用过初始化结果,则无需进行此初始化。【参考方案3】:

回答具体问题(忘记示例代码):是的,您可以引用未初始化的内存,您根本无法取消引用它并期望定义的行为。

【讨论】:

以上是关于引用未初始化的内存而不访问它是不是合法?的主要内容,如果未能解决你的问题,请参考以下文章

野指针与内存操作

我可以通过引用调用placement-new和析构函数吗?

引用的一些规则

引用变量

C ++中未初始化的内存分配

Java未赋值变量的默认初始值