operator[] 的负索引是否定义明确?

Is negative index for operator[] well defined?

我知道这会是非常糟糕的编码风格,但以下代码在我的机器上运行完美。但是行为是否定义明确?便携式?

int main()
{
    int *p = new int[3];
    int *q = &p[2];
    q[-1] = 41;
    std::cout << p[1];
    delete[] p;
}

它非常安全且便携。您只是在使用指针算法来寻址由 new 运算符分配的内存。

您的代码等同于:

int* p = new int[3];
int* q = p + 2;
*(q-1) = 41;

索引运算符 x[idx] 等于 (*(x +idx)) 是的 idx 可能为负。但是,您必须确保取消引用的指针指向有效的内存地址。

请注意,我们可以用多种方式重写它(就像代数一样)。

x[idx] = (*(x +idx)) = (*(idx + x)) = idx[x]

是的,定义明确。内置 operator[] 是根据指针算法定义的。这个:

p[N]

其中p是一个指针,N是一个整数,等价于:

*(p + N)

一个有趣的结果是:

N[p]

也是等价的,因为加法是可交换的。

只要您不尝试取消引用 p 指向的数组边界之外的指针,就绝对没问题。

此外,您可以将指针 q 设置为数组的任何元素,此外,还可以设置为数组后面的一个元素。 (不过,不要试图取消引用超过座位末端的元素。)

别忘了在函数结束时 delete[] p;

这在句法和语义上都有明确的定义。

[expr.sub]/1 (N3337):

The expression E1[E2] is identical (by definition) to *((E1)+(E2)).

因此您的表达式与 *(q-1) = 41; 相同,因此在语法上有效。

[expr.add]/5 (N3337)

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression.

由于 q 指向整数表达式有效大小的数组对象的元素,因此它在语义上是有效的。

根据 C++ 标准(5.2.1 下标)

1 A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall have the type “array of T” or “pointer to T” and the other shall have unscoped enumeration or integral type. The result is of type “T.” The type “T” shall be a completely-defined object type.65 The expression E1[E2] is identical (by definition) to *((E1)+(E2)) ...

因此,您可以使用任何整数类型,包括类型 int 和相应的负值,前提是表达式 *((E1)+(E2)) 的结果格式正确。

请注意,对于用户定义的类型,您可以使用大括号初始化列表作为索引。例如

#include <iostream>

class Point
{
public:    
    Point( int x, int y ) : x( x ), y( y ) {}
    int x, y;
};

class Circle
{
public:    
    Circle( unsigned int r ) : r( r ) {}

    Circle & operator []( Point p )
    {
        std::cout << "Drawing a circle at ( " << p.x << ", " << p.y << " )\n";
        return *this;
    }

    unsigned int r;
};        

int main()
{
    Circle circle( 10 );

    circle[ { 0, 0 } ];
}    

程序输出为

Drawing a circle at ( 0, 0 )