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

Какой из них создаст нулевой указатель?

В стандарте указано, что разыменование нулевого указателя приводит к поведению undefined. Но что такое "нулевой указатель"? В следующем коде мы называем "нулевой указатель":

struct X
{
  static X* get() { return reinterpret_cast<X*>(1); }
  void f() { }
};

int main()
{
  X* x = 0;
  (*x).f(); // the null pointer?  (1)

  x = X::get();
  (*x).f(); // the null pointer?  (2)

  x = reinterpret_cast<X*>( X::get() - X::get() );
  (*x).f(); // the null pointer?  (3)

  (*(X*)0).f(); // I think that this the only null pointer here (4)
}

Моя мысль заключается в том, что разыменование нулевого указателя происходит только в последнем случае. Я прав? Есть ли разница между нулевыми указателями времени компиляции и временем выполнения в соответствии со стандартом С++?

4b9b3361

Ответ 1

Только первый и последний являются нулевыми указателями. Остальные результаты reinterpret_cast и, следовательно, работают с определенными значениями указателей реализации. Является ли поведение undefined для них, зависит от того, есть ли объект по адресу, на который вы положили.

Ответ 2

Целочисленное выражение константы, которое оценивается в 0, является допустимым как нулевой указатель, поэтому первый случай также разыменовывает нулевой указатель.

Указатель, который установлен в 0 через некоторый арифметический расчет, необязательно является нулевым указателем. В большинстве реализаций он будет вести себя так же, как нулевой указатель, но это не гарантируется стандартом.

Ответ 3

Стандарт С++ (2003) 4.10

4.10 Преобразования указателей

1 Константа нулевого указателя является интегральное постоянное выражение (5.19) rvalue целочисленного типа, который оценивает до нуля. Константа нулевого указателя может преобразуется в тип указателя; результатом является значение нулевого указателя этот тип и отличается от любое другое значение указателя на объект или указатель на тип функции. Два нуля значения указателя того же типа должны сравните равные. Преобразование константа указателя null указатель на Квалифицированный тип - это единственный преобразование, а не последовательность преобразование указателя, за которым следует (4.4).

5.2.10 Реинтерпрет

Примечание 64) Преобразование интегральной постоянной выражение (5.19) со значением 0 всегда дает нулевой указатель (4.10), но преобразование других выражений которые нуждаются в нулевом значении не дают нулевой указатель.

1) X* x = 0; (*x).f(); Да. 0 является интегральным постоянным выражением и преобразуется в константу нулевого указателя. Затем константу нулевого указателя можно преобразовать в значение нулевого указателя.

2) x = X::get(); нет, см. примечание 64 в 5.2.10

3) x = reinterpret_cast<X*>( X::get() - X::get() ); нет, см. примечание 64 в 5.2.10

4) ((X) 0).f(); Да.  0 (интегральное постоянное выражение) → константа нулевого указателя → нулевое значение указателя.

Ответ 4

X* x = 0;
(*x).f(); // the null pointer?  (1)

Я думаю, что это относится к разыменованию, хотя f() никогда не использует указатель this, и в X нет виртуальных методов. Мой рефлекс должен был сказать, что это крушение, но теперь, когда я думаю об этом, я не уверен.

x = X::get();
(*x).f(); // the null pointer?  (2)

Вероятно, неверный указатель. не уверен, сработает ли он (см. выше рассуждения).

x = reinterpret_cast<X*>( X::get() - X::get() );
(*x).f(); // the null pointer?  (3)

Скомпилировано ли выражение X::get() - X::get()? Я не думал, что законно вычитать указатель с другого указателя.

ИЗМЕНИТЬ: D'oh! Конечно, это законно. О чем я только думал? Ясно, что я - бордовый.