比较悬空指针是否合法?
int *p, *q;
{
int a;
p = &a;
}
{
int b;
q = &b;
}
std::cout << (p == q) << '\n';
请注意,p
和q
都指向已经消失的对象。这合法吗?
比较悬空指针是否合法?
int *p, *q;
{
int a;
p = &a;
}
{
int b;
q = &b;
}
std::cout << (p == q) << '\n';
请注意,p
和q
都指向已经消失的对象。这合法吗?
p
的值。a
被销毁后,p
获得了所谓的“无效指针值”。引用自N4430(有关N4430状态的讨论请参见下面的“注意”):
使用无效指针值时的行为也在N4430的同一部分中进行了涵盖(C++14 [basic.stc.dynamic.deallocation]/4中几乎相同的文本出现)。当存储区域的持续时间结束时,代表已释放存储的任何部分的地址的所有指针的值都变为无效指针值。
应用于 p == q
: 假设我们在 C++14+N4430 中接受了评估 p
和 q
的结果是实现定义的,并且实现没有定义硬件陷阱发生; [expr.eq]/2说:
如果两个指针都为空,都指向同一个函数或者代表相同的地址(3.9.2),则它们相等,否则它们不相等。
由于评估 p
和 q
时获取的值是实现定义的,因此我们无法确定会发生什么。但它必须是实现定义的或未指定的。
在这种情况下,g++似乎展现出未指定的行为; 根据 -O
开关,我能够让它说 1
或 0
,分别对应于在 a
被销毁后是否重复使用了相同的内存地址来创建 b
。
N4430的注意事项:这是一个针对C++14提出的缺陷解决方案,目前尚未被接受。它清理了很多关于对象生命周期、无效指针、子对象、联合和数组边界访问的措辞。
在C++14文本中,[basic.stc.dynamic.deallocation]/4及其后续段落定义了当使用delete
时会产生一个无效指针值。然而,并没有明确说明同样的原则是否适用于静态或自动存储。
[basic.compound] / 3中有一个“有效指针”的定义,但过于模糊,不能明智地使用。[basic.life]/5(脚注)引用了相同的文本来定义指向具有静态存储期的对象的指针的行为,这表明它应该适用于所有类型的存储。
在N4430中,将文本从该部分移动到上一级,以便明确适用于所有存储持续时间。附有一个注释:
起草说明:这应该适用于所有可以结束的存储持续时间,而不仅仅是动态存储持续时间。在支持线程或分段堆栈的实现中,线程和自动存储可能会像动态存储一样表现。
我的观点:除了说p
获取无效指针值之外,我没有看到任何一致的解释标准(pre-N4430)的方法。这种行为似乎没有被其他部分涵盖,除了我们已经查看过的部分。因此,在这种情况下,我很高兴将N4430措辞视为代表标准意图的方式。
指针包含它们所引用变量的地址。即使曾经存储在那里的变量被释放/销毁/不可用,地址仍然有效。 只要您不尝试使用这些地址上的值,您就是安全的,也就是说*p和*q将是未定义的。
显然,结果是实现定义的,因此如果不想深入研究汇编代码,这个代码示例可以用来研究编译器的特性。
这是否是有意义的做法完全是另一种讨论。
int*f(){int a;return &a;}
优化为return 0;
。 - Marc Glisse