Подтвердить что ты не робот

Учитывая, что p является указателем, "p> nullptr" корректно сформирован?

Указатель p:

char *p ; // Could be any type

Предполагая, что p правильно инициализирован, правильно сформировано следующее:

if (p > 0) // or p > nullptr

В более общем плане он хорошо сформирован для использования реляционного оператора, когда один операнд является указателем, а другой - константой нулевого указателя?

4b9b3361

Ответ 1

В С++ 14 этот код плохо сформирован, но до С++ 14 это был хорошо сформированный код (но результат неуточнен), поскольку отчет о дефектах 583: Сравнение реляционных указателей с константой нулевого указателя:

В C это плохо сформировано (cf C99 6.5.8):

void f(char* s) {
    if (s < 0) { }
}

... но в С++ это не так. Зачем? Кому нужно писать (s > 0) когда они могли так же писать (s!= 0)?

Это было на языке с ARM (и, возможно, раньше); по-видимому, потому, что для преобразования указателей (4.10 [conv.ptr]) для выполнения обоих операндов, когда один из операндов тип указателя. Таким образом, он выглядит как "null-ptr-to-real-pointer-type" преобразование - это переход с другими преобразованиями указателей.

В С++ 14 это было сделано плохо сформированным, когда N3624 был применяется к черновому стандарту С++ 14, который является пересмотром N3478. Предлагаемая резолюция к 583 отмечает:

Эта проблема решается решением проблемы 1512.

и выпуска 1512 предлагаемое разрешение N3478 (N3624 - это ревизия N3478):

Предлагаемая формулировка содержится в документе N3478.

Изменения в разделе 5.9 от С++ 11 до С++ 14

Раздел 5.9 Операторы отношения сильно изменились между стандартным проектом С++ 11 и С++ 14 черновик стандарта, следующие основные моменты выделяют наиболее существенные различия (акцент мой вперед), из параграфа 1:

Операнды должны иметь арифметику, перечисление или тип указателя, или Тип std:: nullptr_t.

изменяется на:

Операнды должны иметь арифметику, перечисление или тип указателя

Таким образом, тип std:: nullptr_t больше не является допустимым операндом, но все еще оставляет 0, который является константой нулевого указателя и поэтому можно преобразовать (раздел 4.10) в тип указателя.

Это описано в параграфе 2, которое в С++ 11 гласит:

[...] Преобразования указателей (4.10) и квалификационные преобразования (4.4) выполняются на операндах указателей (или на операнде указателя и нулевом значении константу указателя или две константы нулевого указателя, по меньшей мере один из который не является неотъемлемым), чтобы привести их к их составному типу указателя. Если один операнд является константой нулевого указателя, тип составного указателя is std:: nullptr_t, если другой операнд также является константой нулевого указателя или, если другой операнд является указателем, тип другого операнд. [...]

это явно предоставляет исключение для операнда константы нулевого указателя, в С++ 14 изменяется следующее:

Обычные арифметические преобразования выполняются на операндах арифметический или перечисляемый тип. Если оба операнда являются указателями, указатель конверсии (4.10) и квалификационные преобразования (4.4) чтобы привести их к их составному указателю (раздел 5). После преобразования, операнды должны иметь один и тот же тип.

В котором нет случая, позволяющего преобразовать 0 в тип указателя. Оба операнда должны быть указателями, чтобы применять преобразования указателей, и требуется, чтобы операнды имели один и тот же тип после конверсий. Это не выполняется в случае, когда один операнд является типом указателя, а другой - константой нулевого указателя 0.

Что делать, если оба операнда являются указателями, а одно - значением нулевого указателя?

R Sahu спрашивает, правильно ли сформирован следующий код?:

char* p = "";
char* q = nullptr;
if ( p > q ) {}

Да, в С++ 14 этот код хорошо сформирован, оба p и q являются указателями, но результат сравнения не указан. Определенные сравнения для двух указателей указаны в параграфе 3 и говорят:

Сравнение указателей с объектами определяется следующим образом:

  • Если два указателя указывают на разные элементы одного и того же массива или на его субобъекты, указатель на элемент с более высоким индекс больше.

  • Если один указатель указывает на элемент массива или на его подобъект, а другой указатель указывает на один из последних элементов массив, последний указатель сравнивается больше.

  • Если два указателя указывают на разные нестатические элементы данных одного и того же объекта или на подобъекты таких элементов, рекурсивно, указатель на более поздний объявленный элемент сравнивается больше, если два члены имеют одинаковый контроль доступа (п. 11) и класс не является объединением.

Значения нулевых указателей здесь и далее не определены в параграфе 4, в котором говорится:

[...] В противном случае результат каждого из операторов не указан.

В С++ 11 он специально делает результаты неопределенными в параграфе 3:

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