为什么 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.

将适用,因为 ab 指向同一数组的元素,即使它们已被强制转换为 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

  1. 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

  1. 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 标准中的原因。