Почему инициализация значения «int * ptr = int ()» не является незаконной?

86

Следующий код (взят отсюда ):

int* ptr = int();

компилируется в Visual C ++ и инициализирует указатель значением.

Как такое возможно? Я имею в виду, что int()дает объект типа, intи я не могу присвоить intуказателю.

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

острый зуб
источник
Не ответ, а отличный вопрос! Я такого не видел.
Джош
6
Так как примитивы имеют «конструктор» в C ++, int()дает значение построено значение int(которое я думаю, что C ++ 03 указано , что) и значение по умолчанию intявляется 0. Это эквивалентноint *ptr = 0;
wkl
7
@EmanuelEy: Нет, любая целочисленная константа с нулевым значением может использоваться как константа нулевого указателя, независимо от того, как указатели фактически реализованы.
Майк Сеймур,
1
@MooingDuck: Я не сказал, что это NULLможет быть ненулевое значение. Я сказал, что это может быть любая целочисленная константа с нулевым значением (включая int()).
Майк Сеймур,
5
@DanielPryden Это использование слова «объект», о котором я раньше не подозревал.
пушистый

Ответы:

110

int()- постоянное выражение со значением 0, поэтому это допустимый способ создания константы нулевого указателя. В конце концов, это просто немного другой способ сказатьint *ptr = NULL;

Джерри Гроб
источник
3
+1, бит константного выражения важен и отсутствует в 2 лучших ответах.
Дэвид Родригес - dribeas
это уходит с C ++ 0x?
Neil G
@NeilG: это остается неизменным в C ++ 11, хотя теперь есть также nullptr, который вы можете использовать вместо 0или NULLв новом коде.
Джерри Коффин,
2
@Nils: Ясность кода и заявление о намерениях посредством кода. Конечно, с C ++ 11 теперь вы хотите использовать nullptr, потому что он также добавляет преимущества дополнительных проверок во время компиляции.
Джамин Грей
3
@Nils, потому что совершенно очевидно, что это 0может означать константу нулевого указателя или число 0, в то время nullptrкак очевидна константа нулевого указателя. Вдобавок, как сказал Джамин, он также имеет «дополнительные проверки во время компиляции». Постарайтесь подумать, прежде чем печатать.
Miles Rout
35

Потому что int()урожаи 0, которые взаимозаменяемы с NULL. NULLсам определяется как 0, в отличие от C, NULLкоторый есть (void *) 0.

Обратите внимание, что это будет ошибкой:

int* ptr = int(5);

и это все равно будет работать:

int* ptr = int(0);

0- это особое постоянное значение, которое может рассматриваться как значение указателя. Константные выражения, которые дают результат 0, такие 1 - 1как допустимые как константы с нулевым указателем.

Благовест Буюклиев
источник
1
Также обратите внимание, что NULL C также не обязательно (void *)0. Это просто реализация, определяемая «целочисленным постоянным выражением со значением 0 или таким выражением, приведенным к типу void *».
Джерри Коффин
@JerryCoffin Я никогда не использовал компилятор C, который определялся NULLкак (void*)0; так было всегда 0(а может быть 0L). (Но потом, к тому времени, когда C90 легализовали (void*)0в C, я уже использовал C ++.)
Джеймс Канце,
1
@JamesKanze: В ubuntu 11.04 и в нашей собственной #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)версии Linux libio.h содержит: текущая версия gcc в ubuntu - 4.5, в нашей системе - 4.0.
Дэвид Родригес - dribeas
5
" 0является особым литералом" - только потому, что это постоянное выражение, и оно имеет специальное значение 0. Не (1-1)менее особенное, это также константа нулевого указателя, и так далее int(). Факт 0быть буквальным является достаточным, но не обязательным условием, чтобы быть постоянным выражением. Что-то вроде этого strlen(""), хотя оно также имеет особое значение 0, не является постоянным выражением и, следовательно, не является константой нулевого указателя.
Стив Джессоп,
@SteveJessop: Я согласен с поправкой, это действительно постоянное значение 0, а не 0буквальное значение.
Благовест Буюклиев
18

Выражение int()вычисляется как постоянное инициализированное по умолчанию целое число, которое является значением 0. Это значение является особенным: оно используется для инициализации указателя на состояние NULL.

Марк Рэнсом
источник
2
Здесь отсутствует очень важная деталь, присутствующая в ответе Джерри: недостаточно того, что выражение дает значение 0, но оно также должно быть константным выражением . Для контрпримера с int f() { return 0; }, выражение f()дает значение 0, но его нельзя использовать для инициализации указателя.
Дэвид Родригес - dribeas
@ DavidRodríguez-dribeas, в спешке дать ответ в самых простых терминах я упустил эту часть. Надеюсь, сейчас это приемлемо.
Марк Рэнсом
13

Из n3290 (C ++ 03 использует аналогичный текст), 4.10 Преобразования указателей [conv.ptr], абзац 1 (выделено мной):

1 Константа нулевого указателя - это целочисленное постоянное выражение (5.19) prvalue целочисленного типа, которое оценивается как ноль, или prvalue типа std :: nullptr_t. Константа нулевого указателя может быть преобразована в тип указателя; результатом является значение нулевого указателя этого типа, которое можно отличить от любого другого значения указателя на объект или типа указателя на функцию. Такое преобразование называется преобразованием нулевого указателя. [...]

int()- такое интегральное постоянное выражение prvalue целочисленного типа, которое оценивается как ноль (это полный рот!), и поэтому может использоваться для инициализации типа указателя. Как видите, 0это не единственное интегральное выражение, имеющее специальный регистр.

Люк Дантон
источник
4

Ну, int - это не объект.

Я полагаю, что здесь происходит то, что вы говорите int * указать на некоторый адрес памяти, определенный int ()

поэтому, если int () создает 0, int * будет указывать на адрес памяти 0

Мегатрон
источник
1
int()безусловно , это объект.
Гонки за легкостью на орбите,
@Tomalak: Я не думаю, что это так. Это временное явление неклассового типа, и я думаю, я прав, говоря, что это не объекты в том, что касается стандарта C ++. Хотя это немного странно, раздел «временные объекты» начинается с осторожного разговора только о временных объектах типа класса, но позже в нем говорится о привязке ссылок, и, конечно, вы можете привязать ссылку к int(). Определите int i;, тогда не вопрос, iэто объект.
Стив Джессоп,
@Steve: Я бы ожидал споров по этому поводу, потому что «объекты» - это область хранения в C ++, а временные библиотеки на самом деле не имеют хранилища, верно? 1.8 / 1 явно не перечисляет временные, но кажется, что есть намерение включить их.
Гонки легкости на орбите
1
@Tomalak: да, действительно, временные файлы неклассового типа не нуждаются в хранилище, если вы не берете ссылку. Неважно, это не имеет большого значения. Утверждение «ну, int не является объектом» истинно только потому, что intэто тип, а не объект. Будь int()дает объект или просто Rvalue не влияет на что - нибудь кто - нибудь говорил в другом месте.
Стив Джессоп,
@Steve: Это многое undebateable :)
светлота Гонка в Orbit