Это неопределенное поведение для сравнения указателей на разные массивы на равенство?

Операторы равенства имеют семантические ограничения реляционных операторов на указатели:

Операторы == (равно) и!= (Не равно) имеют те же семантические ограничения, преобразования и тип результата, что и операторы отношения, за исключением их более низкого приоритета и результата истинности. [C++03 §5.10p2]

А у реляционных операторов есть ограничение на сравнение указателей:

Если два указателя p и q одного и того же типа указывают на разные объекты, которые не являются членами одного и того же объекта или элементов одного и того же массива или на разные функции, или если только один из них имеет значение null, результаты pq, p<= q и p>=q не определены. [§5.9p2]

Это семантическое ограничение, которое "наследуется" операторами равенства?

В частности, учитывая:

int a[42];
int b[42];

Ясно, что (a + 3) <(b + 3) не определено, но также (a + 3) == (b + 3) также не определено?

3 ответа

Решение

Семантика для op== а также op!= прямо скажем, что сопоставление исключает их истинностный результат. Так что вам нужно посмотреть, что определено для их истинного значения результата. Если они говорят, что результат не указан, то он не указан. Если они определяют конкретные правила, то это не так. Это говорит, в частности,

Два указателя одного типа сравниваются равными, если и только если они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес

Результат из операторов равенства (== а также !=) производить указанные результаты до тех пор, пока указатели относятся к объектам одного типа. Учитывая два указателя на один и тот же тип, верно одно из следующих:

  1. оба являются нулевыми указателями, и они сравниваются равными друг другу.
  2. оба указателя на один и тот же объект, и они сравниваются равными друг другу.
  3. они являются указателями на разные объекты, и они не равны друг другу.
  4. по крайней мере, один не инициализирован, и результат сравнения не определен (и, фактически, само сравнение может никогда не произойти - просто попытка прочитать указатель, чтобы выполнить сравнение, дает неопределенное поведение).

При одинаковых ограничениях (оба указателя на один и тот же тип объекта) результат от операторов упорядочения (<, <=, >, >=) указывается только в том случае, если оба они являются указателями на один и тот же объект или на отдельные объекты в одном и том же массиве (и для этого используется "кусок" памяти, выделенный с помощью malloc, new и т. д., квалифицируется как массив). Если указатели ссылаются на отдельные объекты, которые не являются частью одного и того же массива, результат не определен. Если один или оба указателя не были инициализированы, у вас неопределенное поведение.

Несмотря на это, однако, шаблоны сравнения в стандартной библиотеке (std::less, std::greater, std::less_equal а также std::greater_equal) все они дают значимый результат, даже если / если встроенные операторы этого не делают. В частности, они обязаны давать общий заказ. Таким образом, вы можете получить порядок, если хотите, но только не с помощью встроенных операторов сравнения (хотя, конечно, если один или оба указателя не инициализированы, поведение по-прежнему не определено).

Поскольку существует путаница в семантике соответствия, это правила для C++. C использует совершенно другую модель соответствия.

  1. Неопределенное поведение - оксюморонный термин, он означает, что переводчик, а НЕ ваша программа, может делать все, что пожелает. Как правило, это означает, что он может генерировать код, который также будет делать все, что пожелает (но это вычет). Там, где Стандарт говорит, что поведение не определено, текст на самом деле не имеет значения для пользователя в том смысле, что исключение этого текста не изменит требований, которые Стандарт предъявляет к переводчикам.

  2. Плохо сформированная программа означает, что, если не указано иное, поведение переводчика жестко определено: требуется отклонить вашу программу и выдать диагностическое сообщение. Основным особым случаем здесь является Правило с одним определением, если вы нарушаете, что ваша программа некорректна, но диагностика не требуется.

  3. Определенная реализация налагает на переводчика требование, чтобы он содержал документацию, явно указав поведение. В этом особом случае результатом может быть неопределенное поведение, но оно должно быть указано явно.

  4. Unspecified - это глупый термин, который означает, что поведение происходит из набора. В этом смысле четко определенный просто особый случай, когда набор разрешенных поведений содержит только один элемент. Unspecified не требует документации, поэтому в некотором смысле это также означает то же самое, что и реализация, определенная без документации.

В общем, стандарт C++ - это не языковой стандарт, а модель для языкового стандарта. Чтобы сгенерировать актуальный стандарт, вы должны подключить различные параметры. Самым простым из них является ограничение, определяемое реализацией.

В Стандарте есть несколько глупых конфликтов, например, законный переводчик может отклонить каждую явно хорошую программу на C++ на основании того, что вы должны предоставить main() функция, но переводчик поддерживает только идентификаторы из 1 символа. Эта проблема решается понятием QOI или качеством реализации. В основном говорится, кого это волнует, никто не собирается покупать этот компилятор только потому, что он соответствует.

Технически неопределенная природа operator < когда указатели на несвязанные объекты, вероятно, означают: вы получите какой-то результат, который будет либо истинным, либо ложным, но ваша программа не будет аварийно завершена, однако это не является правильным значением unspecified, так что это Defect: unspecified авторы стандартов наложили бремя документирования набора разрешенных поведений, потому что если набор открыт, то это эквивалентно неопределенному поведению.

Я на самом деле предложил std::less как решение проблемы, что некоторые структуры данных требуют, чтобы ключи были полностью упорядочены, но указатели не полностью упорядочены operator <, На большинстве машин используется линейная адресация less такой же как <, но less Операция, скажем, на процессоре x86 потенциально дороже.

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