为什么 C++11 包含一个关于比较 void 指针的奇怪子句?
Why does C++11 contain an odd clause about comparing void pointers?
在检查另一个问题的参考资料时,我注意到 C++11 中的一个奇怪的子句,位于 [expr.rel] ¶3:
Pointers to void
(after pointer conversions) can be compared, with a result defined as follows: If both
pointers represent the same address or are both the null pointer value, the result is true
if the operator is
<=
or >=
and false
otherwise; otherwise the result is unspecified.
这似乎意味着,一旦两个指针被转换为void *
,它们的顺序关系就不再保证;例如,这个:
int foo[] = {1, 2, 3, 4, 5};
void *a = &foo[0];
void *b = &foo[1];
std::cout<<(a < b);
似乎未指定。
有趣的是,这个子句在 C++03 中不存在,在 C++14 中消失了,所以如果我们采用上面的例子并应用 C++14 的措辞,我会说 ¶ 3.1
- If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript compares greater.
将适用,因为 a
和 b
指向同一数组的元素,即使它们已被强制转换为 void *
。请注意,¶3.1 的措辞在 C++11 中几乎相同,但似乎被 void *
子句覆盖。
我的理解对吗?在 C++11 中添加并立即删除的古怪子句有什么意义?或者也许它仍然存在,但是 to/implied 被标准的其他部分移动了?
TL;DR:
- 在 C++98/03 中,该子句不存在,并且标准没有为
void
指针指定关系运算符(核心问题 879,请参阅本文结尾 post);
- 在 C++11 中添加了关于比较
void
指针的奇怪子句来解决它,但这反过来又引发了另外两个核心问题 583 和 1512(见下文);
- 这些问题的解决要求删除该子句并替换为 C++14 标准中的措辞,这允许 "normal"
void *
比较。
核心问题 583:Relational pointer comparisons against the null pointer constant
- Relational pointer comparisons against the null pointer constant Section: 8.9 [expr.rel]
In C, this is ill-formed (cf C99 6.5.8):
void f(char* s) {
if (s < 0) { }
} ...but in C++, it's not. Why? Who would ever need to write (s > 0) when they could just as well write (s != 0)?
This has been in the language since the ARM (and possibly earlier);
apparently it's because the pointer conversions (7.11 [conv.ptr]) need
to be performed on both operands whenever one of the operands is of
pointer type. So it looks like the "null-ptr-to-real-pointer-type"
conversion is hitching a ride with the other pointer conversions.
Proposed resolution (April, 2013):
This issue is resolved by the resolution of issue 1512.
核心问题 1512:Pointer comparison vs qualification conversions
- Pointer comparison vs qualification conversions Section: 8.9 [expr.rel]
According to 8.9 [expr.rel] paragraph 2, describing pointer
comparisons,
Pointer conversions (7.11 [conv.ptr]) and qualification conversions
(7.5 [conv.qual]) are performed on pointer operands (or on a pointer
operand and a null pointer constant, or on two null pointer constants,
at least one of which is non-integral) to bring them to their
composite pointer type. This would appear to make the following
example ill-formed,
bool foo(int** x, const int** y) {
return x < y; // valid ? } because int** cannot be converted to const int**, according to the rules of 7.5 [conv.qual] paragraph 4.
This seems too strict for pointer comparison, and current
implementations accept the example.
Proposed resolution (November, 2012):
解决上述问题的相关摘录见论文:Pointer comparison vs qualification conversions (revision 3).
The following also resolves core issue 583.
Change in 5.9 expr.rel paragraphs 1 to 5:
在本节中,以下语句(C++11 中的 odd 子句已被 删除:
Pointers to void
(after pointer conversions) can be compared, with a result defined as follows: If both pointers represent the same address or are both the null pointer value, the result is true
if the operator is <=
or >=
and false
otherwise; otherwise the result is unspecified
并且添加了以下语句:
- If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript compares greater.
- If one pointer points to an element of an array, or to a subobject thereof, and another pointer points one past the last element of the array, the latter pointer compares greater.
因此在 C++14 (n4140) 部分 [expr.rel]/3 的最终工作草案中,可以找到上述陈述决议的时间。
探究添加这个奇怪的子句的原因让我想到了一个更早的问题 879:Missing built-in comparison operators for pointer types。
该问题的拟议解决方案(2009 年 7 月)导致添加了该条款,该条款于 2009 年 10 月投票进入 WP。
这就是它被包含在 C++11 标准中的原因。
在检查另一个问题的参考资料时,我注意到 C++11 中的一个奇怪的子句,位于 [expr.rel] ¶3:
Pointers to
void
(after pointer conversions) can be compared, with a result defined as follows: If both pointers represent the same address or are both the null pointer value, the result istrue
if the operator is<=
or>=
andfalse
otherwise; otherwise the result is unspecified.
这似乎意味着,一旦两个指针被转换为void *
,它们的顺序关系就不再保证;例如,这个:
int foo[] = {1, 2, 3, 4, 5};
void *a = &foo[0];
void *b = &foo[1];
std::cout<<(a < b);
似乎未指定。
有趣的是,这个子句在 C++03 中不存在,在 C++14 中消失了,所以如果我们采用上面的例子并应用 C++14 的措辞,我会说 ¶ 3.1
- If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript compares greater.
将适用,因为 a
和 b
指向同一数组的元素,即使它们已被强制转换为 void *
。请注意,¶3.1 的措辞在 C++11 中几乎相同,但似乎被 void *
子句覆盖。
我的理解对吗?在 C++11 中添加并立即删除的古怪子句有什么意义?或者也许它仍然存在,但是 to/implied 被标准的其他部分移动了?
TL;DR:
- 在 C++98/03 中,该子句不存在,并且标准没有为
void
指针指定关系运算符(核心问题 879,请参阅本文结尾 post); - 在 C++11 中添加了关于比较
void
指针的奇怪子句来解决它,但这反过来又引发了另外两个核心问题 583 和 1512(见下文); - 这些问题的解决要求删除该子句并替换为 C++14 标准中的措辞,这允许 "normal"
void *
比较。
核心问题 583:Relational pointer comparisons against the null pointer constant
- Relational pointer comparisons against the null pointer constant Section: 8.9 [expr.rel]
In C, this is ill-formed (cf C99 6.5.8):
void f(char* s) { if (s < 0) { } } ...but in C++, it's not. Why? Who would ever need to write (s > 0) when they could just as well write (s != 0)?
This has been in the language since the ARM (and possibly earlier); apparently it's because the pointer conversions (7.11 [conv.ptr]) need to be performed on both operands whenever one of the operands is of pointer type. So it looks like the "null-ptr-to-real-pointer-type" conversion is hitching a ride with the other pointer conversions.
Proposed resolution (April, 2013):
This issue is resolved by the resolution of issue 1512.
核心问题 1512:Pointer comparison vs qualification conversions
- Pointer comparison vs qualification conversions Section: 8.9 [expr.rel]
According to 8.9 [expr.rel] paragraph 2, describing pointer comparisons,
Pointer conversions (7.11 [conv.ptr]) and qualification conversions (7.5 [conv.qual]) are performed on pointer operands (or on a pointer operand and a null pointer constant, or on two null pointer constants, at least one of which is non-integral) to bring them to their composite pointer type. This would appear to make the following example ill-formed,
bool foo(int** x, const int** y) { return x < y; // valid ? } because int** cannot be converted to const int**, according to the rules of 7.5 [conv.qual] paragraph 4.
This seems too strict for pointer comparison, and current implementations accept the example.
Proposed resolution (November, 2012):
解决上述问题的相关摘录见论文:Pointer comparison vs qualification conversions (revision 3).
The following also resolves core issue 583.
Change in 5.9 expr.rel paragraphs 1 to 5:
在本节中,以下语句(C++11 中的 odd 子句已被 删除:
Pointers to
void
(after pointer conversions) can be compared, with a result defined as follows: If both pointers represent the same address or are both the null pointer value, the result istrue
if the operator is<=
or>=
andfalse
otherwise; otherwise the result is unspecified
并且添加了以下语句:
- If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript compares greater.
- If one pointer points to an element of an array, or to a subobject thereof, and another pointer points one past the last element of the array, the latter pointer compares greater.
因此在 C++14 (n4140) 部分 [expr.rel]/3 的最终工作草案中,可以找到上述陈述决议的时间。
探究添加这个奇怪的子句的原因让我想到了一个更早的问题 879:Missing built-in comparison operators for pointer types。 该问题的拟议解决方案(2009 年 7 月)导致添加了该条款,该条款于 2009 年 10 月投票进入 WP。
这就是它被包含在 C++11 标准中的原因。