Определен ли доступ к члену по нулевому указателю в C++?

Является ли вычисление адреса для нулевого указателя определенным поведением в С++? Вот простой пример программы.

struct A { int x; };
int main() {
  A* p = nullptr;
  &(p->x);  // is this undefined behavior?
  return 0;
}

Спасибо.

EDIT Подписка рассматривается в этом другом вопросе< /а>.


person Gregory    schedule 12.06.2020    source источник
comment
Мне кажется УБ. (В первом примере вы имели в виду `&(p-›x);`?)   -  person Eljay    schedule 12.06.2020
comment
@cigien Спасибо за указатель (не каламбур). Это отвечает на второй вопрос, но не на первый вопрос о доступе для членов.   -  person Gregory    schedule 12.06.2020
comment
Определенно UB, нет объекта, на который указывает p, поэтому даже до того, как вы возьмете адрес, выполнение p->x будет таким же, как (*p).x, то есть UB.   -  person cigien    schedule 12.06.2020
comment
Вы задаете здесь два разных вопроса. Доступ для участников и подписка — это не одно и то же. Один из вопросов более тонкий, чем другой.   -  person Brian Bi    schedule 12.06.2020
comment
Отвечает ли это на ваш вопрос: stackoverflow.com/questions/2474018/   -  person M.M    schedule 12.06.2020


Ответы (1)


&(p->x);  // is this undefined behavior?

Стандарт немного расплывчат в этом отношении:

[expr.ref] ... Выражение E1->E2 преобразуется в эквивалентную форму (*(E1)).E2;

[expr.unary.op] Унарный оператор *... результатом является значение lvalue, относящееся к объекту... на который указывает выражение.

В разделе нет явного упоминания UB. Правило в кавычках противоречит тому факту, что нулевой указатель не указывает ни на какой объект. Это можно интерпретировать так: да, поведение не определено.

[expr.unary.op] Результатом унарного оператора & является указатель на его операнд. ... если операнд является значением lvalue типа T, результирующее выражение является значением prvalue типа «указатель на T», результатом которого является указатель на обозначенный объект ([intro.memory]).

Опять же, обозначенного объекта не существует. Обратите внимание, что операнд lvalue ни в коем случае не преобразуется в rvalue, который определенно был бы UB.

Еще в 2000 г. возникла проблема CWG для уточнить, не определена ли косвенность через null. Предложенная резолюция (2004 г.), разъясняющая, что косвенное обращение через null является не UB, по-видимому, не была добавлена ​​в стандарт на данный момент.

Однако, является ли это UB или нет, не имеет большого значения, поскольку вам не нужно этого делать. По крайней мере, результирующий указатель будет недействительным и, следовательно, бесполезным.

Если вы планировали преобразовать указатель в целое число, чтобы получить смещение элемента, в этом нет необходимости, поскольку вместо этого вы можете использовать макрос offsetof из стандартной библиотеки, в которой нет UB.


&(p[1]); // undefined?

Здесь поведение явно не определено:

[expr.sub] ... Выражение E1[E2] идентично (по определению) выражению *((E1)+(E2)), за исключением того, что в случае операнда массива результатом является lvalue, если этот операнд является lvalue и xvalue в противном случае.

[expr.add] Когда выражение J, имеющее целочисленный тип, добавляется или вычитается из выражения P типа указателя, результат имеет тип P.

  • Если P оценивается как значение нулевого указателя, а J оценивается как 0 (не применяется)

  • В противном случае, если P указывает на элемент массива (не применяется)

  • В противном случае поведение не определено.


&(p[0]); // undefined?

В соответствии с предыдущими правилами применяется первый вариант:

Если P оценивается как значение нулевого указателя, а J оценивается как 0, результатом является значение нулевого указателя.

И теперь мы возвращаемся к вопросу о том, является ли косвенность через этот нуль UB. Смотрите начало ответа.

Тем не менее, не имеет большого значения. Нет необходимости писать это, так как это просто излишне сложный способ записи sizeof(int) * i (где i равно 1 и 0 соответственно).

person eerorika    schedule 12.06.2020
comment
Это можно интерпретировать так: да, поведение не определено. -- Другого толкования я не вижу. Такая интерпретация должна была бы объяснить, на какой объект указывает выражение. - person M.M; 12.06.2020
comment
@M.M Достаточно честно. Я удалил это. - person eerorika; 12.06.2020