C++ 运算符[]的负索引是否定义良好?

C++ 运算符[]的负索引是否定义良好?,c++,operator-overloading,language-lawyer,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; } intmain() { int*p=新的int[3]; int*q=&p[2]; q[-1]=41; std::cout它是非常安全和可移植的。您

我知道这将是非常糟糕的编码风格,但下面的代码在我的机器上运行得非常好。但这种行为定义清楚吗?便携式的

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

std::cout它是非常安全和可移植的。您只需使用指针算法来寻址
new
操作符分配的内存

您的代码相当于:

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

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

注意,我们可以用很多方法重写它(就像代数一样)


是的,它定义得很好。内置的
运算符[]
是根据指针算法定义的。这:

p[N]
其中,
p
是指针,
N
是整数,相当于:

*(p + N)
一个有趣的结果是:

N[p]

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

只要您不尝试在
p
指向的数组边界之外取消对指针的引用,这是绝对正确的

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


不要忘记在函数末尾删除[]p;

这在语法和语义上都有很好的定义

[expr.sub]/1(N3337):

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

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

[expr.add]/5(N3337)

将具有整数类型的表达式添加到指针或从指针中减去时,结果为指针操作数的类型。如果指针操作数指向数组对象的某个元素,且数组足够大,则结果指向与原始元素偏移的元素,因此结果的下标差为原始数组元素和原始数组元素等于积分表达式


自从代码> q>代码>指向一个数组对象的元素,它是一个有效的大小,对于它的积分表达式来说,它是语义有效的。

< p>根据C++标准(5.2.1下标)

1后缀表达式后跟方括号中的表达式是 后缀表达式。其中一个表达式的类型应为 “T数组”或“指向T的指针”,另一个应为非范围 枚举或积分类型。结果为“T”类型。类型为 “T”应为完全定义的对象类型。65表达式E1[E2] (根据定义)与*((E1)+(E2))相同

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

考虑到对于用户定义的类型,可以使用大括号init列表作为索引

#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 } ];
}    

只是一张纸巾,从内存中回答,但是我相信Fo[x]在标准中定义为完全等于*(fo+x),其中x是一个整数类型,而fo是指针,所以我认为它在以后任何地方都是合法的。不要在C++中这样做。如果我看到<代码> [-1] < /Cord>我想“哦,我可以很好地阅读最后一个元素”。-就像Python,而不是“它是前面的东西,不管它指向什么”@AlecTeal这真的不是一个很好的理由来否定它。如果我们否定了每一个误导性地类似于另一种流行语言形式的表达式,那么就什么都不会剩下了。我们甚至不能写If语句,因为它们看起来很像Fortan II的算术If。@SteveCox你是对的。未来的程序员将会是使用这个。你是否重载了运算符?后一个例子假设使用了内置的下标运算符。@black:前一个也是。我在文章的顶部提到了这一点。我不确定是否将其称为“up”-shot.。-p是N[p]有用吗?@immibis我决定省去这个问题,因为这个问题是关于负指数的有效性的;间接性是独立的,尽管它显然与第二个引号中定义的结果相关。如果添加关于间接性的信息有助于OP,我很乐意添加它,但我认为没有必要。
#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 )