比较悬空指针是否合法?

fre*_*low 70 c++ pointers language-lawyer dangling-pointer

比较悬空指针是否合法?

int *p, *q;
{
    int a;
    p = &a;
}
{
    int b;
    q = &b;
}
std::cout << (p == q) << '\n';
Run Code Online (Sandbox Code Playgroud)

注意如何既pq点有对象已经消失了.这合法吗?

M.M*_*M.M 57

简介:第一个问题是使用价值是否合法p.

a被破坏之后,p获取所谓的无效指针值.N4430(有关N4430状态的讨论,请参阅下面的"注释"):

当达到存储区域的持续时间的结束时,表示解除分配的存储的任何部分的地址的所有指针的值变为无效的指针值.

使用无效指针值时的行为也在N4430的同一部分中介绍(几乎相同的文本出现在C++ 14 [basic.stc.dynamic.deallocation]/4中):

通过无效指针值间接并将无效指针值传递给释放函数具有未定义的行为.无效指针值的任何其他使用都具有实现定义的行为.

[ 脚注:某些实现可能会定义复制无效指针值会导致系统生成的运行时错误. - 结束脚注]

因此,您需要查阅实现的文档以了解此处应该发生的事情(自C++ 14以来).

上述引号中的术语使用意味着需要进行左值到右值的转换,如C++ 14 [conv.lval/2]:

当对表达式e应用左值到右值转换时,glvalue引用的对象包含无效指针值,该行为是实现定义的.


历史:在C++ 11中,这表示未定义而不是实现定义 ; 它被DR1438改变了.有关完整报价,请参阅此帖子的编辑历史记录.


应用于p == q:假设我们已经在C++ 14 + N4430中接受了评估pq实现定义的结果,并且实现没有定义硬件陷阱发生; [expr.eq]/2说:

两个指针比较相等,如果它们都是null,都指向相同的函数,或者两者都表示相同的地址(3.9.2),否则它们比较不相等.

由于它的实现定义了何时获得的值p以及q评估,我们无法确定这里会发生什么.但它必须是实现定义的或未指定的.

在这种情况下,g ++似乎表现出未指定的行为; 取决于-O开关,我能够让它说1或者0,对应于相同的存储器地址是否被重新用于b之后a被销毁.


关于N4430的注意事项:这是针对C++ 14的建议缺陷解决方案,尚未被接受.它清理了很多围绕对象生命周期,无效指针,子对象,联合和数组边界访问的措辞.

在C++ 14文本中,它在[basic.stc.dynamic.deallocation]/4及后续段落中定义,使用时会出现无效指针值delete.但是,没有明确说明相同的原理是否适用于静态或自动存储.

在[basic.compound]/3中有一个定义"有效指针"但是它太模糊而不能合理使用.[basic.life]/5(脚注)引用同一文本来定义指向对象的指针的行为.静态存储持续时间,这表明它适用于所有类型的存储.

在N4430中,文本从该部分向上移动一级,以便它明确适用于所有存储持续时间.有附注:

起草说明:这应该适用于可以结束的所有存储持续时间,而不仅仅是动态存储持续时间.在支持线程或分段堆栈的实现上,线程和自动存储的行为方式与动态存储的行为方式相同.


我的观点:除了说p获取无效指针值之外,我没有看到任何一致的方式来解释标准(前N4430).除了我们已经看过的内容之外,其他任何部分似乎都没有涵盖这种行为.所以我很高兴在这种情况下将N4430措辞视为代表标准的意图.


  • @LightnessRacesinOrbit请给我一份标准副本,这样我就能做到(如果你能给我发一份印刷版本,那就太棒了,所以我可以在我的答案中显示实际的标准,而不仅仅是*内容*,它出现了与你无关(内容,我的意思)).顺便说一下,菲利普说他也会对印刷品感兴趣. (22认同)
  • 我们其他人不买标准.我们引用最新的免费提供的草案,通常是FDIS左右,但这些事项的措辞不会有太大变化. (17认同)
  • @LightnessRacesinOrbit如果你知道Nxxxx文件,FDIS和官方标准之间的区别,那么你应该认识到与官方标准最接近的N号码,该官方标准是免费在线公开的.期望人们花费数百美元只是为了获得更多的说服力,这相当于一个酒吧赌注的说法,这是荒谬的. (17认同)
  • @zwol:实际上,规定任何进入门槛是合理的,以便将某人击倒,这相当于一个赌注.关键是胜利,而不是正确;-)如果得到正确的答案是重点,那么Lightness当然可以说"......并且公布的标准是相同/不同的",而不是试图抹黑引用而不替换它.我的意思是,我认为Lightness是对的,但菲利普引用的问题是他们不支持他的主张,而不是他们的不准确. (12认同)
  • @LightnessRacesinOrbit我个人对N3936引用很好,除非有人带着C++ 14的副本专门介入并指出差异(其中,AFAIK,没有).C++ 11和N3337也是如此. (9认同)
  • @LightnessRacesinOrbit:看,只需放弃并在stackoverflow上为每个拥有C++标签的人购买标准的打印副本.然后你再也不用要求标准引用了.比谈论它更快,更有效率. (7认同)
  • @LightnessRacesinOrbit比较两个指针并不强制它们指向一个活动对象,这在`[expr.eq] p1`中有所描述:*"相同类型的指针(指针转换后)可以比较相等.两个指针同一类型比较相等,当且仅当它们都为空时,都指向相同的函数,或者两者都代表相同的地址(3.9.2)."* (4认同)
  • 显示标准报价. (3认同)
  • @fredoverflow它同样合法(即:不) (3认同)
  • @Puppy标准报价包括在内 (2认同)
  • @LightnessRacesinOrbit它位于*N3797*的'p2`中,我(错误地)看着*N3337*.@MattMcNabb*lvalue-to-rvalue*转换不是问题,因为指针的值不是*invalid*.与无效指针值和未定义行为相关的引用与诸如`int*p = reinterpret_cast <int*>(0xDEADBEEF); //可能陷阱. (2认同)
  • @FilipRoseen:根据你的论点,无法捕获,因为0xDEADBEEF的内存实际上包含一个字节,而0xDEADBEEF是一个地址. (2认同)
  • @LightnessRacesInOrbit:我担心如果没有统计研究,就没有办法证明人们在随机互联网讨论中购买标准引用. (2认同)