Теперь у нас есть C ++ 11 со многими новыми функциями. Интересным и запутанным (по крайней мере для меня) является новое nullptr
.
Ну, не надо больше для мерзкого макроса NULL
.
int* x = nullptr;
myclass* obj = nullptr;
Тем не менее, я не понимаю, как nullptr
работает. Например, статья в Википедии гласит:
C ++ 11 исправляет это, вводя новое ключевое слово, служащее отличительной константой нулевого указателя: nullptr. Он имеет тип nullptr_t , который неявно конвертируем и сопоставим с любым типом указателя или указателем на член. Он не является неявно конвертируемым или сопоставимым с целочисленными типами, за исключением bool.
Как это ключевое слово и экземпляр типа?
Кроме того, у вас есть еще один пример (помимо Википедии), где nullptr
он превосходит старый добрый 0
?
nullptr
также используется для представления нулевой ссылки для управляемых дескрипторов в C ++ / CLI.nullptr_t
гарантировано иметь только один элемент,nullptr
? Итак, если функция вернуласьnullptr_t
, то компилятор уже знает, какое значение будет возвращено, независимо от тела функции?std::nullptr_t
Можно создать экземпляр @AaronMcDaid , но все экземпляры будут идентичны,nullptr
поскольку тип определяется какtypedef decltype(nullptr) nullptr_t
. Я считаю, что основная причина существования типа заключается в том, что функции могут быть перегружены специально для перехватаnullptr
, если это необходимо. Смотрите здесь для примера.Ответы:
Это не удивительно. Оба
true
иfalse
являются ключевыми словами и в качестве литералов они имеют тип (bool
).nullptr
является литералом-указателем типаstd::nullptr_t
, и это значение (вы не можете получить его адрес, используя&
).4.10
О преобразовании указателя говорит, что значение типаstd::nullptr_t
является константой нулевого указателя и что целая константа нулевого указателя может быть преобразована вstd::nullptr_t
. Противоположное направление не допускается. Это позволяет перегрузить функцию как для указателей, так и для целых чисел, и передать ееnullptr
для выбора версии указателя. ПередачаNULL
или0
будет сбивать с толку выбралint
версию.Приведение
nullptr_t
к целочисленному типу требуетreinterpret_cast
и имеет ту же семантику, что и приведение(void*)0
к целочисленному типу (определена реализация отображения). Неreinterpret_cast
может преобразоватьnullptr_t
в любой тип указателя. Положитесь на неявное преобразование, если это возможно, или используйтеstatic_cast
.Стандарт требует, чтобы это
sizeof(nullptr_t)
былоsizeof(void*)
.источник
cond ? nullptr : 0;
. Удалено из моего ответа.NULL
это даже не гарантируется0
. Может быть0L
, в этом случае вызовvoid f(int); void f(char *);
будет неоднозначным.nullptr
всегда будет поддерживать версию указателя и никогда не вызывать ееint
. Также обратите внимание , чтоnullptr
это конвертируется вbool
(проект говорит , что в4.12
).int
версию. Ноf(0L)
это неоднозначно, потомуlong -> int
чтоlong -> void*
так же, как и одинаково дорого. Так что, если0L
в вашем компиляторе есть NULL , то вызовf(NULL)
будет двусмысленным, учитывая эти две функции. Конечно, не такnullptr
.(void*)0
в C ++. Но его можно определить как любую произвольную константу нулевого указателя, которую любая целочисленная константа со значением 0 иnullptr
выполнит. Итак, определенно нет будет, но может . (Вы забыли пинговать меня между прочим ..)От nullptr: типобезопасный и четкий нулевой указатель :
Другие ссылки:
template
источник
Почему nullptr в C ++ 11? Что это? Почему NULL недостаточно?
Эксперт по С ++ Алекс Аллен прекрасно говорит здесь (мой акцент выделен жирным шрифтом):
Аллен заканчивает свою статью:
(Мои слова):
Наконец, не забывайте, что
nullptr
это объект - класс. Он может быть использован в любом местеNULL
использовалась раньше, но если вам нужно его тип по какой - то причине, это тип можно экстрагироватьdecltype(nullptr)
или непосредственно , как описаноstd::nullptr_t
, что это простоtypedef
изdecltype(nullptr)
.Ссылки:
источник
Если у вас есть функция, которая может получать указатели на несколько типов, вызывать ее с помощью
NULL
неоднозначно. То, как это обходится сейчас, очень хакерское, принимая int и предполагая, что это такNULL
.В результате
C++11
вы могли бы перегружаться,nullptr_t
так чтоptr<T> p(42);
это будет ошибка во время компиляции, а не во время выполненияassert
.источник
NULL
определяется как0L
?nullptr
нельзя присвоить целочисленному типу, такому какint
тип указателя; либо встроенный тип указателя, такой какint *ptr
или интеллектуальный указатель, такой какstd::shared_ptr<T>
Я полагаю, что это важное различие, потому что
NULL
все еще может быть назначено как целочисленному типу, так и указателю, так какNULL
это макрос, расширенный до0
которого может служить как начальным значением дляint
указателя, так и указателем.источник
NULL
не гарантируется расширение до0
.Да. Это также (упрощенный) реальный пример из нашего производственного кода. Он выделялся только потому, что gcc смог выдать предупреждение при кросс-компиляции на платформу с другой шириной регистра (но точно не уверен, почему только при кросс-компиляции с x86_64 до x86 предупреждает
warning: converting to non-pointer type 'int' from NULL
):Рассмотрим этот код (C ++ 03):
Это дает такой вывод:
источник
Ну, в других языках есть зарезервированные слова, которые являются экземплярами типов. Python, например:
Это на самом деле довольно близкое сравнение, потому что
None
обычно используется для чего-то, что не было инициализировано, но в то же время сравнения, такие какNone == 0
ложные.С другой стороны, в простом C,
NULL == 0
вернул бы true IIRC, потому чтоNULL
это просто макрос, возвращающий 0, который всегда является неверным адресом (AFAIK).источник
NULL
это макрос, который расширяется до нуля, константный ноль, приведенный к указателю, создает нулевой указатель. Нулевой указатель не обязательно должен быть нулем (но часто это так), ноль не всегда является недопустимым адресом, и непостоянный ноль, приведенный к указателю, не должен быть нулевым, а нулевой указатель приведен к целое число не должно быть нулем. Надеюсь, я все понял, ничего не забыв. Ссылка: c-faq.com/null/null2.htmlЭто ключевое слово, потому что стандарт будет указывать его как таковой. ;-) Согласно последнему публичному проекту (n2914)
Это полезно, поскольку неявно преобразуется в целочисленное значение.
источник
Допустим, у вас есть функция (f), которая перегружена и принимает как int, так и char *. До C ++ 11, если вы хотели вызвать его с нулевым указателем и использовали NULL (т. Е. Значение 0), вы бы вызвали перегруженный для int:
Это, вероятно, не то, что вы хотели. C ++ 11 решает это с помощью nullptr; Теперь вы можете написать следующее:
источник
Позвольте мне сначала дать вам реализацию простой
nullptr_t
nullptr
Тонкий пример идиомы Resolver Return Type для автоматического вывода нулевого указателя правильного типа в зависимости от типа экземпляра, которому он назначается.nullptr
назначается целочисленный указатель, создаетсяint
экземпляр типа для функции преобразования шаблонов. И то же самое относится и к указателям на метод.nullptr
как это целочисленный литерал со значением ноль, вы не можете использовать его адрес, который мы сделали, удалив & оператор.Зачем нам нужно
nullptr
в первую очередь?NULL
есть некоторая проблема с этим как ниже:1️⃣ Неявное преобразование
2️⃣ Неоднозначность вызова функций
3️⃣ Перегрузка конструктора
String s((char*)0))
. Е.источник
Раньше 0 было единственным целочисленным значением, которое могло использоваться в качестве инициализатора без приведения для указателей: вы не можете инициализировать указатели с другими целочисленными значениями без приведения. Вы можете рассматривать 0 как одноэлементное выражение, синтаксически похожее на целочисленный литерал. Может инициировать любой указатель или целое число. Но удивительно, вы обнаружите, что он не имеет четкого типа: это
int
. Так почему же 0 может инициализировать указатели, а 1 - нет? Практический ответ состоял в том, что нам нужны средства определения нулевого значения указателя, а прямое неявное преобразованиеint
в указатель подвержено ошибкам. Таким образом 0 стал настоящим чудовищным чудаком из доисторической эпохи.nullptr
было предложено быть реальным одноэлементным представлением constexpr нулевого значения для инициализации указателей. Его нельзя использовать для непосредственной инициализации целых чисел, а устранение неоднозначностей, связанных с определением, можно определить как библиотеку с использованием синтаксиса std, но семантически выглядело как отсутствующий основной компонент. в настоящее время устарела в пользу , если какая-то библиотека не решит определить его как .NULL
в терминах 0.nullptr
NULL
nullptr
nullptr
источник
Вот заголовок LLVM.
(многое можно найти быстро
grep -r /usr/include/*`
)Одна вещь, которая выскакивает, это
*
перегрузка оператора (возвращение 0 намного удобнее, чем segfaulting ...). Другое дело, что он не выглядит совместимым с хранением адреса вообще . Который, по сравнению с тем, как он обрабатывает void * и передает результаты NULL в обычные указатели в качестве значений часовых, очевидно, уменьшит фактор «никогда не забывай, это может быть бомба».источник
NULL не обязательно должен быть 0. Пока вы используете всегда NULL и никогда не 0, NULL может принимать любое значение. Предполагается, что вы программируете микроконтроллер von Neuman с плоской памятью, вектор прерываний которого равен 0. Если NULL равен 0 и что-то записывает в нулевой указатель, микроконтроллер выходит из строя. Если NULL, скажем, 1024, а в 1024 есть зарезервированная переменная, запись не приведет к сбою, и вы можете обнаружить назначения NULL Pointer изнутри программы. Это бессмысленно для ПК, но для космических зондов, военной или медицинской техники важно не разбиться.
источник