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

Почему вы не можете взять адрес 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 динамически назначать адрес точно в срок для сравнения и т.д.? Или (вероятно, более вероятно), возможно, компилятор заставляет временную копию базового объекта?

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

4b9b3361

Ответ 1

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

Значения не имеют адресов; объекты.

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

Ответ 2

Если вы после стандартного ответа, § 18.2/9 строго фиксирует ваши наблюдения:

Хотя адрес nullptrs не может быть принят, адрес другого объекта nullptr_t, который является значением l, может приниматься.

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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