c++ - programacion - ¿Puede ptrdiff_t representar todas las restas de punteros a elementos del mismo objeto de matriz?
vectores en c++ pdf (2)
¿Es posible incluso que el resultado de
ij
no esté en el rango de valores representables deptrdiff_t
?
Sí, pero es poco probable.
De hecho, [support.types.layout]/2
no dice mucho, excepto que las reglas apropiadas sobre la resta de punteros y ptrdiff_t
se definen en [expr.add]
. Así que veamos esta sección.
[expr.add]/5
Cuando se restan dos punteros a elementos del mismo objeto de matriz, el tipo de resultado es un tipo integral con signo definido por la implementación; este tipo será del mismo tipo que se define como
std::ptrdiff_t
en el encabezado<cstddef>
.
En primer lugar, tenga en cuenta que el caso donde i
y j
son índices subíndices de diferentes matrices no se considera. Esto permite tratar ij
como PQ
donde P
es un puntero al elemento de una matriz en el subíndice i
Q
es un puntero al elemento de la misma matriz en el subíndice j
. De hecho, restar dos punteros a elementos de diferentes matrices es un comportamiento indefinido :
[expr.add]/5
Si las expresiones
P
yQ
apuntan, respectivamente, a los elementosx[i]
yx[j]
del mismo objeto de matrizx
, la expresiónP - Q
tiene el valori−j
; de lo contrario, el comportamiento no está definido .
Como conclusión, con la notación definida anteriormente, ij
y PQ
se definen para tener el mismo valor, siendo este último del tipo std::ptrdiff_t
. Pero no se dice nada sobre la posibilidad de que este tipo tenga tal valor. Sin embargo, esta pregunta puede responderse con la ayuda de std::numeric_limits
; especialmente, uno puede detectar si una matriz some_array
es demasiado grande para std::ptrdiff_t
para contener todas las diferencias de índice:
static_assert(std::numeric_limits<std::ptrdiff_t>::max() > sizeof(some_array)/sizeof(some_array[0]),
"some_array is too big, subtracting its first and one-past-the-end element indexes "
"or pointers would lead to undefined behavior as per [expr.add]/5."
);
Ahora, en el objetivo habitual, esto normalmente no ocurriría como sizeof(std::ptrdiff_t) == sizeof(void*)
; lo que significa que una matriz debería ser estúpidamente grande para que ptrdiff_t
desborde. Pero no hay garantía de eso.
Para la resta de punteros i
y j
a elementos del mismo objeto de matriz, la nota en [expr.add # 5] dice:
[ Nota: si el valor i-j no está en el rango de valores representables de tipo
std::ptrdiff_t
, el comportamiento no está definido. - nota final ]
Pero dado [support.types.layout#2] , que establece que (el énfasis es mío):
- El tipo
ptrdiff_t
es un tipo de entero con signo definido por la implementación que puede contener la diferencia de dos subíndices en un objeto de matriz, como se describe en [expr.add] .
¿Es posible incluso que el resultado de ij
no esté en el rango de valores representables de ptrdiff_t
?
PD: Me disculpo si mi pregunta es causada por mi pobre conocimiento del idioma inglés.
EDITAR: Relacionado: ¿Por qué el tamaño máximo de una matriz es "demasiado grande"?
Creo que es un error de las palabras.
La regla en [expr.add] se hereda de la misma regla para la resta del puntero en el estándar C. En el estándar C, ptrdiff_t
no necesita mantener ninguna diferencia de dos subíndices en un objeto de matriz.
La regla en [support.types.layout] proviene de Core Language Issue 1122 . Agregó definiciones directas para std::size_t
y std::ptrdiff_t
, que se supone que resuelve el problema de la definición circular. No veo que haya ninguna razón (al menos no mencionada en ningún documento oficial) para hacer que std::ptrdiff_t
mantenga la diferencia de dos subíndices en un objeto de matriz. Supongo que solo usa una definición incorrecta para resolver el problema de definición circular.
Como otra evidencia, [diff.library] no menciona ninguna diferencia entre std::ptrdiff_t
en C ++ y ptrdiff_t
en C. Como en C ptrdiff_t
no tiene tal restricción, en C ++ std::ptrdiff_t
no debería tener esa restricción también.