给定int ** p1和const int ** p2是p1 == p2是否良好形成?

时间:2015-03-12 19:39:23

标签: c++ c++11 language-lawyer c++14

给出以下功能:

void g(int **p1, const int**p2)
{
   if (p1 == p2) { }  
}

clang返回3.0版)会产生此警告( see it live ):

warning: comparison of distinct pointer types ('int **' and 'const int **')
uses non-standard composite pointer type 'const int *const *' 
[-Wcompare-distinct-pointer-types]
  if (p1 == p2) { }
      ~~ ^ ~~

使用-pedantic-errors标志会将其变为错误。根据标准,gcc回4.3.6 )和Visual Studio 2013 )都不会产生警告,是比较:< / p>

p1 == p2

结构良好?

更一般地说,如果两个多级指针的 cv-qualifications 不同于第一级,那么通过等式运算符或关系运算符进行比较是否很好?

1 个答案:

答案 0 :(得分:24)

在C ++ 14之前,这个案例是形成错误的,一些例外的更一般的案例也是不正确的。这在defect report 1512: Pointer comparison vs qualification conversions 中有所说明,其中包含:

  

根据5.9 [expr.rel]第2段,描述指针   比较,

     
    

指针操作数(或更高版本)执行指针转换(4.10 [conv.ptr])和限定转换(4.4 [conv.qual])     指针操作数和空指针常量,或两个空指针     将它们带到的常数,其中至少有一个是非整数的     他们的复合指针类型。

  
     

这似乎使以下示例格式错误,

bool foo(int** x, const int** y) {
   return x < y;  // valid ?
}
     

因为int **不能转换为const int **,根据   4.4 [conv.qual]第4段的规则。这似乎过于严格   指针比较,当前的实现接受了这个例子。

缺陷报告指出虽然这是不正确的,但实施方案接受了这种比较。这个clang commit表示它被视为一个扩展名,表示gccEDG也将此视为扩展,可能是Visual Studio的情况。

标准由N3624: Core Issue 1512: Pointer comparison vs qualification conversions解决,其中说:

  

本文介绍了必要的工作草案修改   解决核心问题583和1512.特别是,它使

     

[...]

     

void g(int **p1, const int**p2)
{
   if (p1 == p2) { ... }
}
     

良好的。

同时请注意,在meeting it was accepted中,有人指出这只是编纂了现有做法。

在标准的其他更改中,此段落已添加到5 [expr] 部分的末尾,其中包含新术语 cv-combined type

  

两种类型T1和T2的cv组合类型是类似于T1的类型T3   其cv资格签名(4.4)是:

     
      
  • 对于每个j&gt; 0,cv3,j是cv1,j和cv2,j;
  • 的并集   
  • 如果得到的cv3,j不同于cv1,j或cv2,j,则将const添加到每个cv3,k为0 <0。 k&lt;学家
  •   
     

[注:给出类似的T1类型   和T2,这种结构确保两者都可以转换为T3。   -end note]两个操作数p1和p2的复合指针类型   分别具有类型T1和T2,其中至少一个是指针   或指向成员类型或std :: nullptr_t的指针是:

     
      
  • 如果p1和p2都是空指针常量,则为std :: nullptr_t;
  •   
  • 如果p1或p2分别是空指针常量,T2或T1;
  •   
  • 如果T1或T2是“指向cv1 void的指针”而另一种类型是“指向cv2 T的指针”,“指向cv12 void的指针”,其中cv12是cv1的并集   cv2;
  •   
  • 如果T1是“指向cv1 C1的指针”而T2是“指向cv2 C2的指针”,其中C1是与C2相关的参考或C2是与C1相关的引用(8.5.3),   cv-组合型T1和T2或cv-组合型T2和   分别为T1;
  •   
  • 如果T1是“指向cv1 U1类型C1的成员的指针”,T2是“指向cv2 U2类型C2的成员的指针”,其中C1是与C2相关的参考或   C2与参考相关的C1(8.5.3),cv组合类型的T2和   分别为T1或cv组合型T1和T2;
  •   
  • 如果T1和T2是类似的多级混合指针和指向成员类型的指针(4.4),则是cv-combined类型的T1和T2;
  •   
  • 否则,需要确定复合指针类型的程序是不正确的。
  •   
     

[例如:

    typedef void *p;
    typedef const int *q;
    typedef int **pi;
    typedef const int **pci;
     

p和q的复合指针类型是“指向const void的指针”;该   pi和pci的复合指针类型是“指向const指针的指针   const int“。 - 例子]