运营商的负指数是否定义良好?
我知道这将是非常糟糕的编码风格,但下面的代码在我的机器上完美运行。 但是,行为是否明确? 便携式?
int main() { int *p = new int[3]; int *q = &p[2]; q[-1] = 41; std::cout << p[1]; delete[] p; }
这在句法和语义上都有明确的定义。
[expr.sub] / 1(N3337):
expression式
E1[E2]
与*((E1)+(E2))
相同(根据定义*((E1)+(E2))
。
所以你的expression与*(q-1) = 41;
,所以在句法上是有效的。
[expr.add] / 5(N3337)
当具有整数types的expression式被添加到指针或从指针中减去时,结果具有指针操作数的types。 如果指针操作数指向数组对象的一个元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果数组元素和原始数组元素的下标之差等于整数expression式。
由于q
指向您的整数expression式的有效大小的数组对象的元素,它在语义上是有效的。
是的,它是明确的。 内置operator[]
是根据指针运算来定义的。 这个:
p[N]
其中p
是一个指针, N
是一个整数,相当于这个:
*(p + N)
这个有趣的结果是:
N[p]
也是等价的,因为加法是可交换的。
根据C ++标准(5.2.1下标)
1后缀expression式后跟方括号中的expression式是后缀expression式。 其中一个expression式的types应该是“T的数组”或者“指向T的指针”,另一个expression式应该是非范型的枚举或者整型 。 结果是“T”型。“T”型应该是一个完全定义的对象types。
因此,只要expression式*((E1)+(E2))
的结果是正确的,就可以使用任何整数types,包括int
types和相应的负值。
考虑到对于用户定义的types,你可以使用一个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 ( " << px << ", " << py << " )\n"; return *this; } unsigned int r; }; int main() { Circle circle( 10 ); circle[ { 0, 0 } ]; }
程序输出是
Drawing a circle at ( 0, 0 )
索引运算符x[idx]
等于(*(x +idx))
,是的, idx
可能是负数。 但是,您必须确保解除引用的指针指向有效的内存地址。
请注意,我们可以用许多方式重写它(就像代数一样)。
x[idx] = (*(x +idx)) = (*(idx + x)) = idx[x]
只要你不试图在p
指向的数组的边界之外解引用一个指针,这是绝对没问题的。
此外,您可以将指针q设置为数组的任何元素,另外还可以将其指定给数组中的一个元素。 (不要试图通过座位的尽头解除引用元素。)
不要忘记delete[] p;
在你的函数结束。
它非常安全和便携。 您只是使用指针算术来寻址由new
运算符分配的内存。
您的代码相当于:
int* p = new int[3]; int* q = p + 2; *(q-1) = 41;