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

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

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

41

Решение

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

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

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

78

Другие решения

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

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

Альтернативно, § 2.14.7 говорит об этом nullptr:

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

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

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

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

27

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

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

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

10

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

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

4
По вопросам рекламы [email protected]