Supongamos que tiene una matriz:
int array[SIZE];o
int *array = new(int[SIZE]); ¿C o C++ garantizan que array < array + SIZE , y si es así, dónde?
Entiendo que, independientemente de la especificación del idioma, muchos sistemas operativos garantizan esta propiedad al reservar la parte superior del espacio de direcciones virtuales para el kernel. Mi pregunta es si esto también está garantizado por el idioma , en lugar de solo por la gran mayoría de las implementaciones.
Como ejemplo, suponga que el kernel de un sistema operativo tiene poca memoria y, a veces, entrega la página más alta de memoria virtual a los procesos de usuario en respuesta a las solicitudes mmap de memoria anónima. Si malloc o ::operator new[] llama directamente a mmap para la asignación de una gran matriz, y el final de la matriz linda con la parte superior del espacio de direcciones virtuales de modo que la array + SIZE se ajusta a cero, ¿esto equivale a una cantidad no -cumplimiento de la aplicación de la lengua?
Aclaración
Tenga en cuenta que la pregunta no se refiere a array+(SIZE-1) , que es la dirección del último elemento de la matriz. Se garantiza que ese será mayor que array . La pregunta es sobre un puntero uno más allá del final de una matriz , o también p+1 cuando p es un puntero a un objeto que no es una matriz (que la sección del estándar apuntada por la respuesta seleccionada deja en claro que se trata de la misma manera ).
Stackoverflow me ha pedido que aclare por qué esta pregunta no es la misma que esta . La otra pregunta es cómo implementar la ordenación total de punteros. Esa otra pregunta esencialmente se reduce a cómo podría una biblioteca implementar std::less de modo que funcione incluso para punteros a objetos asignados de manera diferente, que el estándar dice que solo se pueden comparar por igualdad, no mayor y menor que.
Por el contrario, mi pregunta era si siempre se garantiza que uno más allá del final de una matriz sea mayor que la matriz. Si la respuesta a mi pregunta es sí o no, en realidad no cambia la forma en que implementaría std::less , por lo que la otra pregunta no parece relevante. Si es ilegal comparar con uno más allá del final de una matriz, entonces std::less simplemente podría exhibir un comportamiento indefinido en este caso. (Además, normalmente la biblioteca estándar es implementada por las mismas personas que el compilador, por lo que es libre de aprovechar las propiedades del compilador en particular).
C requiere esto. La Sección 6.5.8 párrafo 5 dice:
punteros a elementos de matriz con valores de subíndice más grandes comparar punteros mayores que a elementos de la misma matriz con valores de subíndice más bajos
Estoy seguro de que hay algo análogo en la especificación de C++.
Este requerimiento previene efectivamente la asignación de objetos que se envuelven alrededor del espacio de direcciones en hardware común, porque sería poco práctico implementar toda la contabilidad necesaria para implementar el operador relacional de manera eficiente.
Si. De la sección 6.5.8 párrafo 5 .
Si la expresión P apunta a un elemento de un objeto de matriz y la expresión Q apunta al último elemento del mismo objeto de matriz, la expresión de puntero Q+1 es mayor que P.
La array expresiones es P. La array + SIZE - 1 apunta al último elemento de la array , que es Q. Por lo tanto:
array + SIZE = array + SIZE - 1 + 1 = Q + 1 > P = array
Se garantiza que la matriz tenga espacio de memoria consecutivo dentro. después de c++03, se garantiza que los vectores también tendrán uno para su &vec[0] ... &vec[vec.size() - 1] . Esto automáticamente significa que lo que estás preguntando es cierto.
se llama almacenamiento contiguo. se puede encontrar aquí para los vectores
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0944r0.html
Los elementos de un vector se almacenan de forma contigua, lo que significa que si v es un vector<T, Allocator> donde T es un tipo distinto de bool, entonces obedece a la identidad &v[n] == &v[0] + n para todo 0 <= n < v.tamaño(). Presuntamente, cinco años más de estudio de las interacciones de la contigüidad con el almacenamiento en caché dejaron en claro al WG21 que la contigüidad debía ser obligatoria y que la implementación de vectores no contiguos debería prohibirse claramente.
último es de documentos estándar. C++03 He acertado.
Esto se define en C++, desde 7.6.6.4 (p139 del borrador actual de C++23 ):
Cuando a una expresión P de tipo apuntador se le suma o resta una expresión J de tipo entero, el resultado es de tipo P.
(4.1) — Si P se evalúa como un valor de puntero nulo y J se evalúa como 0, el resultado es un valor de puntero nulo.
(4.2) — De lo contrario, si P apunta a un elemento de arreglo i de un objeto de arreglo x con n elementos (9.3.4.5) las expresiones P + J y J + P (donde J tiene el valor j) apuntan a (posiblemente- hipotético) elemento de matriz i + j de x si 0 <= i + j <= n y la expresión P - J apunta al (posiblemente hipotético) elemento de matriz i − j de x si 0 <= i − j <= n .
(4.3) — De lo contrario, el comportamiento no está definido.
Tenga en cuenta que 4.2 tiene explícitamente "<= n", no "< n". No está definido para ningún valor mayor que size(), pero está definido para size().
El orden de los elementos de la matriz se define en 7.6.9 (p141):
(4.1) Si dos punteros apuntan a diferentes elementos de la misma matriz, oa subobjetos del mismo, se requiere el puntero al elemento con el subíndice más alto para comparar mayor.
Lo que significa que el elemento hipotético n comparará más que la matriz en sí (elemento 0) para todos los casos bien definidos de n > 0.
La garantía no es válida para el caso int *array = new(int[SIZE]); cuando SIZE es cero.
Se requiere que el resultado de new int[0] sea un puntero válido al que se le puede agregar 0 , pero array == array + SIZE en este caso, y una prueba estrictamente menor que arrojará false .
La regla relevante en C++ es [expr.rel]/4.1 :
Si dos punteros apuntan a diferentes elementos de la misma matriz, oa subobjetos del mismo, se requiere el puntero al elemento con el subíndice más alto para comparar mayor.
La regla anterior parece cubrir solo los punteros a elementos de matriz, y array + SIZE no apunta a un elemento de matriz. Sin embargo, como se menciona en la nota al pie , un puntero pasado el final se trata aquí como si fuera un elemento de matriz. La regla de idioma relevante está en [basic.compound]/3 :
A efectos de la aritmética de punteros ([expr.add]) y la comparación ([expr.rel], [expr.eq]), un puntero más allá del final del último elemento de una matriz
xde n elementos se considera equivalente a un puntero a un elemento de matriz hipotético n dexy un objeto de tipoTque no es un elemento de matriz se considera que pertenece a una matriz con un elemento de tipoT.
Entonces C++ garantiza que array + SIZE > array (al menos cuando SIZE > 0 ), y que &x + 1 > &x para cualquier objeto x .