Это законно:
int array[5];
int *array_begin = &array[0];
int *array_end = &array[5];
Раздел 5.2.1 Подписка Выражение E1 [E2] идентично (по определению) * ((E1) + (E2))
Таким образом, мы можем сказать, что array_end также эквивалентен:
int *array_end = &(*((array) + 5)); // or &(*(array + 5))
Раздел 5.3.1.1 Унарный оператор '*': унарный оператор * выполняет косвенное обращение: выражение, к которому он применяется, должно быть указателем на тип объекта или
указатель на тип функции и результатом является lvalue, ссылающееся на объект или функцию , на которые указывает выражение.
Если тип выражения «указатель на T», тип результата - «T». [Примечание: указатель на неполный тип (другое
чем cv void) может быть разыменовано. Полученное таким образом значение может быть использовано ограниченным образом (для инициализации ссылки, для
пример); это значение не должно быть преобразовано в значение, см. 4.1. - конец примечания]
Важная часть вышесказанного:
«результатом является lvalue, ссылающееся на объект или функцию».
Унарный оператор '*' возвращает lvalue со ссылкой на int (без разыменования). Затем унарный оператор '&' получает адрес lvalue.
Пока нет разыменования указателя вне границ, тогда операция полностью охватывается стандартом, и все поведение определено. Таким образом, по моему прочтению вышеизложенное совершенно законно.
Тот факт, что многие алгоритмы STL зависят от правильного определения поведения, является своего рода подсказкой, которую комитет по стандартам уже об этом сказал, и я уверен, что есть кое-что, что это явно освещает.
В разделе комментариев ниже представлены два аргумента:
(пожалуйста, прочитайте: но это долго, и мы оба в конечном итоге троллить)
Аргумент 1
это незаконно из-за параграфа 5.7 параграфа 5
Когда выражение с целочисленным типом добавляется или вычитается из указателя, результат имеет тип операнда указателя. Если операнд-указатель указывает на элемент объекта массива, а массив достаточно велик, результат указывает на смещение элемента от исходного элемента, так что разность индексов результирующего и исходного элементов массива равна интегральному выражению. Другими словами, если выражение P указывает на i-й элемент объекта массива, выражения (P) + N (эквивалентно, N + (P)) и (P) -N (где N имеет значение n) указывают соответственно i + n-м и i-n-м элементам массива, если они существуют. Кроме того, если выражение P указывает на последний элемент объекта массива, выражение (P) +1 указывает один за последним элементом объекта массива, а если выражение Q указывает на один последний элемент последнего элемента массива, выражение (Q) -1 указывает на последний элемент объекта массива. Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или одного последнего
последний элемент объекта массива, оценка не должна производить переполнение; в противном случае поведение не определено.
И хотя раздел актуален; это не показывает неопределенное поведение. Все элементы в массиве, о котором мы говорим, находятся либо внутри массива, либо за концом (что хорошо определено в предыдущем абзаце).
Аргумент 2:
Второй аргумент, представленный ниже: *
- оператор разыменования.
И хотя это общий термин, используемый для описания оператора *; этот термин намеренно избегают в стандарте, так как термин «отсылка» недостаточно четко определен с точки зрения языка и того, что это означает для базового оборудования.
ХотьОбращение с памятью за пределами массива определенно является неопределенным поведением. Я не уверен, что unary * operator
обращается к памяти (читает / записывает в память) в этом контексте (не так, как определяет стандарт). В этом контексте (как определено стандартом (см. 5.3.1.1)) unary * operator
возвращает lvalue referring to the object
. В моем понимании языка это не доступ к основной памяти. Результат этого выражения затем немедленно используется оператором unary & operator
, который возвращает адрес объекта, на который ссылается lvalue referring to the object
.
Представлено много других ссылок на Википедию и неканонические источники. Все из которых я нахожу неактуальным. C ++ определяется стандартом .
Вывод:
Я готов признать, что есть много частей стандарта, которые я, возможно, не учел и могу доказать, что мои приведенные выше аргументы неверны. НЕ указаны ниже. Если вы покажете мне стандартную ссылку, которая показывает, что это UB. Я буду
- Оставьте ответ.
- Вставить все заглавные буквы, это глупо, и я не прав для всех читать.
Это не аргумент:
Не все во всем мире определяется стандартом C ++. Открой свой разум.