Почему нельзя взять адрес nullptr?

В стандарте С++ 11 я не понимаю, почему использование адреса nullptr запрещено, тогда как одному разрешено брать адрес своих собственных экземпляров std::nullptr_t. Помимо того факта, что nullptr является зарезервированным ключевым словом, есть ли какое-либо обоснование для этого решения?

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

decltype(nullptr)* func(const decltype(nullptr) &nref) noexcept
{
    return const_cast<decltype(nullptr)*>(reinterpret_cast<const decltype(nullptr)*>(&nref));
}

Мне пришлось использовать reinterpret_cast для параметра, потому что без него я получал истерическую ошибку:

error: invalid conversion from 'std::nullptr_t*' to 'std::nullptr_t*' [-fpermissive]

Когда я вызываю эту функцию, передавая nullptr напрямую, я каждый раз получаю другой адрес. Назначается ли nullptr динамическим адресом как раз вовремя для сравнений и т. д.? Или (вероятнее всего), возможно, компилятор принудительно создает временную копию базового объекта?

Конечно, все это не является жизненно важной информацией, мне просто интересно, почему было реализовано это конкретное ограничение (и, следовательно, почему я вижу такое поведение).


person monkey0506    schedule 07.01.2013    source источник
comment
nullptr — это значение. Вы не можете взять адрес тех. +1 за сообщение об ошибке.   -  person chris    schedule 07.01.2013


Ответы (4)


Это то же самое, что и невозможность получить адрес 5, хотя вы можете взять адрес int, присвоив ему значение 5. Неважно, что у nullptr_t нет альтернативного значения.

У значений нет адресов; объекты делают.

Временный объект создается, когда вы передаете такое значение параметру const & или иным образом привязываете значение к константной ссылке, например, с помощью static_cast< T const & >( … ) или объявления именованной ссылки T const & foo = …;. Адрес, который вы видите, является временным.

person Potatoswatter    schedule 07.01.2013
comment
Спасибо! На самом деле я еще немного покопался и наткнулся на этот ответ на связанный вопрос. Затем до меня дошло, что nullptr задуман как литерал нулевого указателя, да? Имеет смысл, что вы не сможете взять адрес литерала. :) - person monkey0506; 07.01.2013
comment
Да, nullptr — это ключевое слово, представляющее литерал. Так же, как true и false&true тоже нельзя). - person aschepler; 07.01.2013
comment
Ага! :D Я думаю, что когда я читал нулевой указатель constant, я читал его просто как логическую константу, а не литеральную константу. - person monkey0506; 07.01.2013
comment
Кстати, поздравляю с новым топ-ответом :) - person chris; 07.01.2013

Если вам нужен стандартный ответ, § 18.2/9 довольно прямо излагает ваши наблюдения:

Хотя адрес nullptr не может быть взят, можно взять адрес другого объекта nullptr_t, который является lvalue.

В качестве альтернативы, в § 2.14.7 говорится о nullptr:

Литерал указателя — это ключевое слово nullptr. Это значение типа std::nullptr_t.

Так что же такое prvalue? § 3.10/1 отвечает, что:

Значение prvalue («чистое» значение r) — это значение r, которое не является значением x. [ Пример: результатом вызова функции, тип возвращаемого значения которой не является ссылкой, является значение prvalue. Значение литерала, такого как 12, 7.3e5 или true, также является значением prvalue. — конец примера]

Будем надеяться, что попытка получить адрес любой из этих вещей в примере будет иметь больше смысла в том, почему вы не можете взять адрес nullptr. Это часть тех примеров!

person chris    schedule 07.01.2013
comment
Ах, до сих пор я не знал, что такое prvalue, +1. - person Seth Carnegie; 07.01.2013
comment
@SethCarnegie, мне нравится их определение. Иногда, когда я просматриваю стандарт, чтобы полностью определить что-то, это очень напоминает мне рекурсию. - person chris; 07.01.2013
comment
@SethCarnegie, я забыл об этом, но если это не просто prvalues, взгляните на этот вопрос для тех, кому он нравится. - person chris; 11.01.2013
comment
@chris, о, круто, я этого не видел, в избранное. Кроме того, мне интересно, что лучший ответ (на этот вопрос) имеет примерно на 30 голосов больше, чем ваш. Я не уверен, почему это так. - person Seth Carnegie; 11.01.2013
comment
@SethCarnegie, я ответил немного позже, после того, как было подано довольно много голосов, но то, что действительно заставляет вас охнуть в этом ответе, - это последняя цитата, которая, если вы заметили, сделала лучший ответ. , просто более явно и вне летучих мышей. Я имел в виду это как доказательство того, что можно следовать стандарту, чтобы увидеть, почему это недействительно. - person chris; 11.01.2013

nullptr — это (буквальная) константа, и у них нет адреса памяти, как у любой другой буквальной константы в вашем коде. Он похож на 0, но имеет специальный тип std::nullptr_t вместо void*, чтобы избежать проблем с перегрузкой (указатели против целых чисел).

Но если вы определяете свою собственную переменную со значением nullptr, у нее есть адрес памяти, поэтому вы можете взять ее адрес.

То же самое относится и к любой другой литеральной константе (которая в C++ относится к категории prvalue) любого другого типа, поскольку литеральные константы не хранятся в вашей программе (только как части выражений, где они встречаются), поэтому говорить об адресах не имеет смысла. Однако постоянные переменные имеют адреса, чтобы указать на разницу.

person leemes    schedule 07.01.2013

И true, и false являются ключевыми словами и как литералы имеют тип ( bool ). nullptr - это литерал указателя типа std::nullptr_t, и это значение prvalue (вы не можете взять его адрес с помощью &), также nullptr является значением prvalue, поэтому вы не можете взять его адрес, литеральные константы не хранятся в вашей программе.

Не имеет смысла иметь адрес.

person Ahmed Kato    schedule 07.01.2013