Is it even possible for the result of i-j
not to be in the range of representable values of ptrdiff_t
?
Yes, but it's unlikely.
In fact, [support.types.layout]/2
does not say much except the proper rules about pointers subtraction and ptrdiff_t
are defined in [expr.add]
. So let us see this section.
When two pointers to elements of the same array object are subtracted, the type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as std::ptrdiff_t
in the <cstddef>
header.
First of all, note that the case where i
and j
are subscript indexes of different arrays is not considered. This allows to treat i-j
as P-Q
would be where P
is a pointer to the element of an array at subscript i
and Q
is a pointer to the element of the same array at subscript j
. In deed, subtracting two pointers to elements of different arrays is undefined behavior:
If the expressions P
and Q
point to, respectively, elements x[i]
and x[j]
of the same array object x
, the expression P - Q
has the value i−j
; otherwise, the behavior is undefined.
As a conclusion, with the notation defined previously, i-j
and P-Q
are defined to have the same value, with the latter being of type std::ptrdiff_t
. But nothing is said about the possibility for this type to hold such a value. This question can, however, be answered with the help of std::numeric_limits
; especially, one can detect if an array some_array
is too big for std::ptrdiff_t
to hold all index differences:
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."
);
Now, on usual target, this would usually not happen as sizeof(std::ptrdiff_t) == sizeof(void*)
; which means an array would need to be stupidly big for ptrdiff_t
to overflow. But there is no guarantee of it.
i-j
(and they do not in fact provide such ptrdiff_t). The intent of the standard is not to make stuff difficult and expensive, or to make most existing implementations non-conforming, but rather the oposite. So yeah, it "can hold the difference"... when it can. – Bribei
andj
are valid indices for the same array, that aptrdiff_t
can represent the result ofi - j
. The first quote amounts to the reverse requirement - thati - j
must also be able to be represented in aptrdiff_t
or the behaviour is undefined (I'd argue the first note is redundant given the presence of the second, but it probably reduces opportunities for language lawyers to find obscure exploitable loopholes in the language). – Strachan