Может ли ptrdiff_t представлять все вычитания указателей на элементы одного и того же объекта массива?

Для вычитания указателей i а также j к элементам одного и того же объекта массива примечание в [expr.add # 5] гласит:

[ Замечания: Если значение I-J не находится в диапазоне представимых значений типа std​::​ptrdiff_­t, поведение не определено. - конечная нота ]

Но учитывая [Support.types.layout # 2], в котором говорится, что (акцент мой):

  1. Тип ptrdiff_­t является определяемым реализацией целочисленным типом со знаком, который может держать разница двух индексов в объекте массива, как описано в [Expr.add].

Возможно ли это даже в результате i-j не быть в диапазоне представимых значений ptrdiff_t?

PS: Я прошу прощения, если мой вопрос вызван моим плохим пониманием английского языка.

РЕДАКТИРОВАТЬ: Связанные с: Почему максимальный размер массива "слишком большой"?

32

Решение

Возможно ли это даже в результате i-j не быть в диапазоне представимых значений ptrdiff_t?

Да, но вряд ли.

По факту, [support.types.layout]/2 не говорит много, кроме правильных правил вычитания указателей и ptrdiff_t определены в [expr.add], Итак, давайте посмотрим на этот раздел.

[expr.add]/5

Когда вычитаются два указателя на элементы одного и того же объекта массива, тип результата является определяемым реализацией знаковым целочисленным типом; этот тип должен быть того же типа, который определен как std​::​ptrdiff_­t в <cstddef> заголовок.

Прежде всего, обратите внимание, что случай, когда i а также j Индексы индексов разных массивов не рассматриваются. Это позволяет лечить i-j как P-Q будет где P указатель на элемент массива в нижнем индексе i а также Q указатель на элемент тот же самый массив в нижнем индексе j, На самом деле вычитание двух указателей на элементы разных массивов неопределенное поведение:

[expr.add]/5

Если выражения P а также Q указать соответственно на элементы x[i] а также x[j] одного и того же объекта массива x, выражение P - Q имеет значение i−j
; в противном случае поведение не определено.

В заключение, с обозначениями, определенными ранее, i-j а также P-Q определены как имеющие одинаковое значение, причем последний имеет тип std::ptrdiff_t. Но ничего не сказано о возможности для этого типа иметь такое значение. На этот вопрос, однако, можно ответить с помощью std::numeric_limits; особенно, можно обнаружить, если массив some_array является слишком большой за std::ptrdiff_t чтобы сохранить все различия индекса:

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.");

Теперь, на обычной цели, это обычно не происходит, как sizeof(std::ptrdiff_t) == sizeof(void*); что означает, что массив должен быть тупо большим для ptrdiff_t переполниться. Но нет никаких гарантий на это.

5

Другие решения

Я думаю, что это ошибка формулировок.

Правило в [expr.add] унаследовано от того же правила для вычитания указателя в стандарте C. В стандарте C ptrdiff_t не требуется хранить разницу двух индексов в объекте массива.

Правило в [support.types.layout] исходит от Базовая языковая проблема 1122. Добавлены прямые определения std::size_t а также std::ptrdiff_t, которая должна решить проблему кругового определения. Я не вижу никаких причин (по крайней мере, не упомянутых ни в одном официальном документе) сделать std::ptrdiff_t держать любую разницу двух индексов в объекте массива. Я думаю, что он просто использует неправильное определение для решения проблемы кругового определения.

В качестве еще одного доказательства, [Diff.library] не упоминает никакой разницы между std::ptrdiff_t в C ++ и ptrdiff_t в к. с в к ptrdiff_t не имеет такого ограничения, в C ++ std::ptrdiff_t не должно быть такого ограничения тоже.

1

По вопросам рекламы [email protected]