我可以为C++本地变量地址做出哪些假设?

4

我想知道,在循环块内部是否可以重复使用指向变量的指针。

int *ptr = nullptr;
for (int i = 0; i < 5; ++i) {
    int j = 5;
    if (!ptr) ptr = &j;
    cout << *ptr << endl;
}

我相信这个代码可以在所有编译器上运行,但它符合标准吗?


为什么要写低效率或者可疑的代码呢?只需要使用&j替代ptr,就可以避免这种问题。 - Ed Heal
@AdrianoRepetti,实际上,在ideone中它可以工作:http://ideone.com/gCCXjn - alexeykuzmin0
编译器(带优化)可能首先将其转换为类似以下内容:int j = 5; int* ptr = &j; cout << *ptr << endl;cout重复5次)。然后,如果在任何其他地方都没有使用ptr,它将简单地生成cout << 5 << endl;(重复五次)。请参见此帖子,但尤其要阅读此帖子中的评论。您的假设已经被打破(在那种情况下)。 - Adriano Repetti
如果从i计算j并且使用*ptr而不是函数调用,则示例会更好。然后,合理的优化程序可以展开循环,并可能重叠计算j(和/或将某些计算视为从未使用),但无论如何都可能不会将它们全部放在同一位置。 - JSF
为了使代码不“工作”,它不仅必须将j的另一个迭代放在不同的位置,还必须销毁放置在第一个j的陈旧位置的5。理论上,那个5不应该还在那里,但实际上它会存在。因此,即使编译器展开循环并重叠工作以使所有j不能放在同一位置,陈旧的5仍然可以代替每个有效的5。无论多么健壮,它仍然是未定义的。但是,一个不太健壮的版本会更好地解决这个问题。 - JSF
显示剩余3条评论
1个回答

6
不行,它不起作用。
在第二次迭代中,“ptr”指向第一次迭代的“j”,而这个值已经不存在了。在那时解除引用“ptr”的行为是未定义的。对于第一次迭代之后的所有迭代,也是如此。

1
很可能,新的迭代j会被放置在与先前迭代j完全相同的内存地址上,因此,我认为这在大多数现代编译器中实际上会起作用。但是,是的,这是未定义的行为,不符合标准。 - alexeykuzmin0
@alexeykuzmin0 不要对这些微妙而不明确的细节做出假设。一个_现代_编译器可能会为这种情况做任何它想做的事情。如果我必须手写汇编,我甚至不会将j放入内存中,编译器会比我做得更好... - Adriano Repetti
@rodrigo:我从来没有说过这是正确的 - 我永远不会编写这样的代码或在代码审查中接受它。只是可能在大多数情况下这会起作用。 - alexeykuzmin0
我认为你应该只关注未定义行为,因为这个简单的例子在你听说过的任何编译器中都可以工作。构建一个更复杂的相同未定义行为的示例需要大量的努力,才能真正失败。(让优化器在循环的后续迭代中将至少一次取地址的本地变量放置在不同的位置)。 - JSF
@JSF并不是不可能构建这样的例子 - Adriano Repetti
显示剩余3条评论

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