Может ли 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: Я прошу прощения, если мой вопрос вызван моим плохим пониманием английского языка.

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

2 ответа

Решение

Возможно ли это даже в результате 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 переполниться. Но нет никаких гарантий на это.

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

Правило в [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 не должно быть такого ограничения тоже.

Другие вопросы по тегам