Ptrdiff t peut-il représenter toutes les soustractions de pointeurs vers des éléments du même objet de tableau?
pour la soustraction des pointeurs i
et j
aux éléments du même objet de tableau la note dans [expr.ajouter#5] se lit:
[ Note: Si la valeur i-j n'est pas dans la gamme de représentable, les valeurs de type
std::ptrdiff_t
, le comportement est indéfini. - note finale ]
mais donné [soutien.type.disposition n ° 2] , qui stipule que ( accent le mien):
- le type
ptrdiff_t
est un type entier signé défini par implémentation qui peut contenir la différence de deux indices dans un objet array, tel que décrit dans [expr.ajouter] .
est-il même possible pour le résultat de i-j
Non être dans l'intervalle des valeurs représentatives de ptrdiff_t
?
PS: je m'excuse si ma question est causée par ma mauvaise compréhension de la langue anglaise.
EDIT: Related: Pourquoi est la taille maximale d'un tableau est "trop grand"?
2 réponses
est-il même possible que le résultat de
i-j
ne soit pas dans l'intervalle des valeurs représentatives deptrdiff_t
?
Oui, mais c'est peu probable.
en fait, [support.types.layout]/2
ne dit pas grand chose sauf les règles appropriées sur la soustraction de pointeurs et ptrdiff_t
sont définis dans [expr.add]
. Donc, nous allons voir cette section.
[expr.add]/5
lorsque deux pointeurs vers des éléments du même objet array sont soustraits, le type du résultat est un type intégral signé défini par implémentation; ce type doit être le même type qui est défini comme
std::ptrdiff_t
dans l'en-tête<cstddef>
.
tout d'abord, notez que le cas où i
et j
sont des indices en indice de différents tableaux n'est pas considéré. Cela permet de traiter 151910920" P-Q
est lorsque P
est un pointeur vers l'élément d'un tableau à l'indice i
et Q
est un pointeur vers l'élément de le même tableau à l'indice j
. En effet, soustraire deux pointeurs à des éléments de tableaux différents est comportement non défini :
[expr.add]/5
si les expressions
P
etQ
pointent respectivement vers les élémentsx[i]
etx[j]
du même objet de tableaux
, l'expressionP - Q
a la valeuri−j
; sinon, le comportement est non défini .
comme conclusion, avec la notation définie précédemment, i-j
et P-Q
sont définis pour avoir la même valeur, ce dernier étant de type std::ptrdiff_t
. Mais rien n'est dit sur la possibilité, pour ce type d'organiser une telle valeur. On peut cependant répondre à cette question à l'aide de std::numeric_limits
; en particulier, on peut détecter si un tableau some_array
est trop grand pour std::ptrdiff_t
pour tenir toutes les différences d'index:
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."
);
maintenant, sur la cible habituelle, cela ne se produirait généralement pas comme sizeof(std::ptrdiff_t) == sizeof(void*)
; ce qui signifie qu'un tableau devrait être stupidement grand pour ptrdiff_t
à débordement. Mais il n'y a aucune garantie.
je pense que c'est un bug des formulations.
La règle dans [expr.add] est hérité de la même règle pour la soustraction de pointeur dans le standard C. Dans la norme C, ptrdiff_t
n'est pas requis pour contenir une différence de deux indices dans un objet array.
La règle [de soutien.type.mise en page] provient de Core Question de la Langue 1122 . Il a ajouté des définitions directes pour std::size_t
et std::ptrdiff_t
, qui est supposé pour résoudre le problème de la définition circulaire. Je ne vois aucune raison (du moins pas mentionnée dans un document officiel) de faire std::ptrdiff_t
tenir une différence de deux indices dans un objet array. Je suppose qu'il utilise une définition incorrecte pour résoudre le problème de la définition circulaire.
Comme une autre preuve, [diff.bibliothèque] ne mentionne aucune différence entre std::ptrdiff_t
en C++ et ptrdiff_t
en C. Depuis en C ptrdiff_t
n'a pas une telle contrainte, en C++ std::ptrdiff_t
ne devrait pas avoir une telle contrainte aussi.