Як ініціалізація значення “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: Ні, будь-яка цілочисельна константа з нульовим значенням може використовуватися як константа нульового покажчика, незалежно від того, як насправді реалізовані вказівники.
Mike Seymour

1
@MooingDuck: Я не сказав, що це NULLможе бути ненульове значення. Я сказав, що це може бути будь-яка ціла константа з нульовим значенням (що включає int()).
Mike Seymour

5
@DanielPryden Це вживання слова "об'єкт", про яке я раніше не знав.
пухнастий

Відповіді:


110

int()є константним виразом зі значенням 0, тому це дійсний спосіб створення константи нульового покажчика. Зрештою, це лише дещо інший спосіб сказатиint *ptr = NULL;


3
+1, біт константного виразу важливий і відсутній у 2-х найкращих відповідях.
Девід Родрігес - dribeas

це зникає з C ++ 0x?
Neil G

@NeilG: Це залишається незмінним у C ++ 11, хоча зараз також є a nullptr, який ви можете використовувати замість 0або NULLв новому коді.
Джеррі Коффін

2
@Nils: Чіткість коду та проголошення ваших намірів за допомогою коду. Звичайно, з C ++ 11 тепер ви хочете використовувати nullptr, оскільки він також передає перевагу додаткових перевірок часу компіляції в суміш.
Jamin Gray

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
Також зауважте, що значення N не має значення NULL (void *)0. Це просто реалізація, визначена "цілочисельний константний вираз зі значенням 0, або такий вираз, що використовується для введення void *".
Джеррі Коффін,

@JerryCoffin Я ніколи не використовував компілятор C, який визначався NULLяк (void*)0; це було завжди 0(а може, і 0L). (Але тоді, на той час, коли C90 зробив (void*)0легальний на C, я вже використовував C ++.)
James Kanze

1
@JamesKanze: В ubuntu 11.04 та нашому власному ароматі Linux, libio.h містить: #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)поточна версія gcc в ubuntu - 4,5, у нашій системі - 4,0.
Девід Родрігес - dribeas

5
" 0є спеціальним літералом" - лише тому, що це константний вираз, і воно має спеціальне значення 0. (1-1)однаково особливе, це також константа нульового покажчика, і так само int(). Факт 0буквеності є достатньою, але не необхідною умовою, щоб бути постійним виразом. Щось на зразок strlen(""), хоча воно також має особливе значення 0, не є постійним виразом і, отже, не є константою нульового покажчика.
Steve Jessop

@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) першого значення цілого типу, яке обчислюється нулем, або першого значення типу std :: nullptr_t. Нульова константа вказівника може бути перетворена в тип вказівника; результатом є значення нульового покажчика цього типу, яке можна відрізнити від будь-якого іншого значення покажчика об’єкта або типу покажчика функції. Таке перетворення називається перетворенням нульового покажчика. [...]

int()є таким інтегральним константним виразом першого значення цілочисельного типу, яке обчислюється рівним нулю (це просто!), і, отже, може використовуватися для ініціалізації типу покажчика. Як бачите, 0це не єдиний інтегральний вираз, який має особливу форму.


4

Well int isn't an object.

I beleive what's happening here is you're telling the int* to point to some memory address determined by int()

so if int() creates 0, int* will point to memory address 0


1
int() most certainly is an object.
Lightness Races in Orbit

@Tomalak: I don't think it is. It's a temporary of non-class type, and I think I'm right in saying that these are not objects as far as the C++ standard is concerned. It's a bit odd, though, the section on "temporary objects" starts out carefully talking only about temporaries of class type, but later on it talks about binding references, and of course you can bind a reference to int(). Define int i;, then no question, i is an object.
Steve Jessop

@Steve: Я би очікував лише дискусій з цього приводу в тому, що "об'єкти" - це область зберігання в C ++, і тимчасові компанії насправді не мають сховища, так? 1.8 / 1 не містить явного переліку тимчасових програм, але складається враження, ніби має намір їх включити.
Гонки легкості на орбіті

1
@Tomalak: так, тимчасові некласові типи не потребують сховища, якщо ви не візьмете посилання. Неважливо, хоча це не має великого значення. Твердження "ну int не є об'єктом" є істинним лише тому, що intє типом, а не об'єктом. Будь int()дає об'єкт або просто Rvalue не впливає на що - небудь хто - небудь говорив в іншому місці.
Steve Jessop

@Steve: That much is undebateable :)
Lightness Races in Orbit
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.