比较悬空指针是否合法? [英] Is it legal to compare dangling pointers?

查看:132
本文介绍了比较悬空指针是否合法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比较悬空指针是否合法?

  int * p,* q; 
{
int a;
p =& a;
}
{
int b;
q =& b;
}
std :: cout<< (p == q)<< '\\\
';

请注意 p q 指向已经消失的对象。这是合法吗?

解决方案

简介:第一个问题是使用价值



之后 destroy, p 获取所谓的无效指针值。引自 N4430 (有关N4430的状态的讨论,请参阅注意):


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


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


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



[脚注:

因此你需要参考你的实现文档来找出这里应该发生什么。



以上引号中的使用一词意义需要进行左值到右值转换,如C ++ 14 [conv.lval / 2]中所示:


当对表达式e应用左值到右值转换,并且[...] glvalue引用的对象包含无效的指针值时,行为是实现 - 这表示未定义,而不是实现定义;它已被 DR1438 更改。






申请到 p == q 假设我们在C ++ 14 + N4430中接受评估 p q 是实现定义的,并且实现未定义发生硬件陷阱; [expr.eq] / 2说:


如果两个指针都为空,都指向同一个函数,


由于实现定义了当<$ p c $ c> p q 进行评估,我们不能确定这里会发生什么。但它必须是实现定义的或未指定的。



g ++在这种情况下似乎表现出未指定的行为;取决于 -O 开关,我可以让它说 1 0 之后是否重新使用相同的存储器地址/ code>,这对应于 b

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



在C ++ 14文本中,在[basic.stc.dynamic.deallocation] / 4和后续段落中定义了一个无效的指针值出现时使用 delete



在[basic.compound] / 3中有一个定义有效的指针,但是它并没有清楚地说明这个原理是否适用于静态或自动存储。它太模糊以致于无法使用。[basic.life] / 5(footnote)指的是相同的文本来定义指向静态存储持续时间的对象的行为,这表明它意在应用于所有类型的存储。



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


制图备注:这应适用于可以结束的所有存储持续时间,只是动态存储持续时间。在支持线程或分段堆栈的实现上,线程和自动存储的行为可以与动态存储相同。







我的意见:我没有看到任何解释标准(N4430之前)的方式,除了 p 获取无效的指针值。除了我们已经看过的内容,这个行为似乎没有被任何其他章节覆盖。所以我很乐意把N4430的措辞看作是这种情况下标准的意图。





Is it legal to compare dangling pointers?

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

Note how both p and q point to objects that have already vanished. Is this legal?

解决方案

Introduction: The first issue is whether it is legal to use the value of p at all.

After a has been destroyed, p acquires what is known as an invalid pointer value. Quote from N4430 (for discussion of N4430's status see the "Note" below):

When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of the deallocated storage become invalid pointer values.

The behaviour when an invalid pointer value is used is also covered in the same section of N4430 (and almost identical text appears in C++14 [basic.stc.dynamic.deallocation]/4):

Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

[ Footnote: Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault. — end footnote ]

So you will need to consult your implementation's documentation to find out what should happen here (since C++14).

The term use in the above quotes means necessitating lvalue-to-rvalue conversion, as in C++14 [conv.lval/2]:

When an lvalue-to-rvalue conversion is applied to an expression e, and [...] the object to which the glvalue refers contains an invalid pointer value, the behaviour is implementation-defined.


History: In C++11 this said undefined rather than implementation-defined; it was changed by DR1438. See the edit history of this post for the full quotes.


Application to p == q: Supposing we have accepted in C++14+N4430 that the result of evaluating p and q is implementation-defined, and that the implementation does not define that a hardware trap occurs; [expr.eq]/2 says:

Two pointers compare equal if they are both null, both point to the same function, or both represent the same address (3.9.2), otherwise they compare unequal.

Since it's implementation-defined what values are obtained when p and q are evaluated, we can't say for sure what will happen here. But it must be either implementation-defined or unspecified.

g++ appears to exhibit unspecified behaviour in this case; depending on the -O switch I was able to have it say either 1 or 0, corresponding to whether or not the same memory address was re-used for b after a had been destroyed.


Note about N4430: This is a proposed defect resolution to C++14, that hasn't been accepted yet. It cleans up a lot of wording surrounding object lifetime, invalid pointers, subobjects, unions, and array bounds access.

In the C++14 text, it is defined under [basic.stc.dynamic.deallocation]/4 and subsequent paragraphs that an invalid pointer value arises when delete is used. However it's not clearly stated whether or not the same principle applies to static or automatic storage.

There is a definition "valid pointer" in [basic.compound]/3 but it is too vague to use sensibly.The [basic.life]/5 (footnote) refers to the same text to define the behaviour of pointers to objects of static storage duration, which suggests that it was meant to apply to all types of storage.

In N4430 the text is moved from that section up one level so that it does clearly apply to all storage durations. There is a note attached:

Drafting note: this should apply to all storage durations that can end, not just to dynamic storage duration. On an implementation supporting threads or segmented stacks, thread and automatic storage may behave in the same way that dynamic storage does.


My opinion: I don't see any consistent way to interpret the standard (pre-N4430) other than to say that p acquires an invalid pointer value. The behaviour doesn't seem to be covered by any other section besides what we have already looked at. So I am happy to treat the N4430 wording as representing the intent of the standard in this case.


这篇关于比较悬空指针是否合法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆