运算符[]的负指数是否定义明确?

use*_*183 40 c++ operator-overloading language-lawyer

我知道编码风格会很糟糕,但是下面的代码在我的机器上运行得很好.但这种行为是否定义明确?便携式?

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

Tar*_*ama 44

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

[expr.sub]/1(N3337):

表达式E1[E2](根据定义)相同*((E1)+(E2)).

所以你的表达式是一样的*(q-1) = 41;,语法上也是如此.

[expr.add]/5(N3337)

当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式.

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


Ben*_*ley 18

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

p[N]
Run Code Online (Sandbox Code Playgroud)

where p是一个指针,N是一个整数,相当于:

*(p + N)
Run Code Online (Sandbox Code Playgroud)

一个有趣的结果就是:

N[p]
Run Code Online (Sandbox Code Playgroud)

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

  • @black:前者也是如此.我在帖子的顶部提到了这一点. (3认同)

Vla*_*cow 7

根据C++标准(5.2.1订阅)

1后缀表达式后跟方括号中的表达式是后缀表达式.其中一个表达式应具有"T的数组"类型或"指向T的指针",另一个表达式应具有未映射的枚举或整数类型.结果是类型"T".类型"T"应该是完全定义的对象类型.65表达式E1 [E2]与*((E1)+(E2))相同(...(E1)+(E2))...

所以你可以使用任何整数类型,包括类型int和相应的负值,只要表达的结果*((E1)+(E2))是良好的形式.

考虑到对于用户定义的类型,您可以使用brace-init-list作为索引.例如

#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 } ];
}    
Run Code Online (Sandbox Code Playgroud)

程序输出是

Drawing a circle at ( 0, 0 )
Run Code Online (Sandbox Code Playgroud)