Перейти к содержимому

Чем отличается null от nullptr

  • автор:

nullptr (C++/CLI и C++/CX)

Ключевое слово nullptr представляет значение указателя NULL. Значение пустого указателя показывает, что тип дескриптора объекта, внутреннего указателя или собственного указателя не указывает на объект.

Используется nullptr с управляемым или машинным кодом. Компилятор выводит соответствующие, но различные инструкции для управляемых и машинных значений пустых указателей. Дополнительные сведения об использовании версии этого ключевого слова в соответствии со стандартом ISO C++ см. в разделе nullptr.

__nullptr ключевое слово — это ключевое слово, относящуюся к корпорации Майкрософт, которая имеет то же значение, что nullptr и код, но применяется только к машинному коду. Если вы используете nullptr собственный код C/C++, а затем компилируете с параметром компилятора /clr , компилятор не может определить, указывает ли nullptr собственное или управляемое значение указателя NULL. Чтобы сделать намерение понятным компилятору, используйте nullptr для указания управляемого значения или __nullptr для указания собственного значения.

Ключевое слово nullptr эквивалентен Nothing в Visual Basic и null в C#.

Использование

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

Ключевое слово nullptr не является типом и не поддерживается для использования:

  • sizeof
  • typeid
  • throw nullptr (однако throw (Object^)nullptr; будет работать)

Ключевое слово nullptr можно использовать в инициализации следующих типов указателей:

  • собственного указателя;
  • дескриптора среды выполнения Windows;
  • управляемого дескриптора;
  • управляемого внутреннего указателя.

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

Вызовы функций для языков, использующих значения пустых указателей для проверки ошибок, должны правильно интерпретироваться.

Невозможно инициализировать дескриптор до нуля; можно использовать только nullptr . При присвоении константы 0 дескриптору объекта создаются упакованный тип Int32 и приведение к типу Object^ .

Пример: nullptr ключевое слово

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

// mcpp_nullptr.cpp // compile with: /clr value class V <>; ref class G <>; void f(System::Object ^) <> int main() < // Native pointer. int *pN = nullptr; // Managed handle. G ^pG = nullptr; V ^pV1 = nullptr; // Managed interior pointer. interior_ptrpV2 = nullptr; // Reference checking before using a pointer. if (pN == nullptr) <> if (pG == nullptr) <> if (pV1 == nullptr) <> if (pV2 == nullptr) <> // nullptr can be used as a function argument. f(nullptr); // calls f(System::Object ^) > 

Пример. Использование и ноль nullptr взаимозаменяемого использования

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

// mcpp_nullptr_1.cpp // compile with: /clr class MyClass < public: int i; >; int main()
pMyClass == nullptr pMyClass == 0 pMyClass == nullptr pMyClass == 0 

Пример. Интерпретация nullptr как дескриптор

В следующем примере кода показано, что nullptr интерпретируется как дескриптор любого типа или собственного указателя на любой тип. В случае перегрузки функции с дескрипторами различных типов создается ошибка неоднозначности. Необходимо nullptr явно привести к типу.

// mcpp_nullptr_2.cpp // compile with: /clr /LD void f(int *)<> void f(int ^)<> void f_null() < f(nullptr); // C2668 // try one of the following lines instead f((int *) nullptr); f((int ^) nullptr); >

Пример: Приведение nullptr

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

// mcpp_nullptr_3.cpp // compile with: /clr /LD using namespace System; template void f(T) <> // C2036 cannot deduce template type because nullptr can be any type int main() < f((Object ^) nullptr); // T = Object^, call f(Object ^) // Delete the following line to resolve. f(nullptr); f(0); // T = int, call f(int) >

Пример. Передача nullptr в качестве параметра функции

В следующем примере кода показано, что nullptr можно использовать в качестве параметра функции.

// mcpp_nullptr_4.cpp // compile with: /clr using namespace System; void f(Object ^ x) < Console::WriteLine("test"); >int main()
test 

Пример. Инициализация по умолчанию

В следующем примере кода показано, что при объявлении дескрипторов и не явной инициализации они инициализированы nullptr по умолчанию.

// mcpp_nullptr_5.cpp // compile with: /clr using namespace System; ref class MyClass < public: void Test() < MyClass ^pMyClass; // gc type if (pMyClass == nullptr) Console::WriteLine("NULL"); >>; int main() < MyClass ^ x = gcnew MyClass(); x ->Test(); > 
NULL 

Пример. Назначение собственного указателя nullptr

В следующем примере кода показано, что nullptr при компиляции с помощью собственного указателя /clr можно назначить указатель.

// mcpp_nullptr_6.cpp // compile with: /clr int main()

Требования

Параметр компилятора: необязателен; поддерживается всеми параметрами создания кода, включая /ZW и /clr .

c++ Null vs nullptr

Добрый день, вчера пытался разобраться в чем преимущество (конкретно, а не в виде абстрактных понятий типа ООП и прочая эзотерика) nullptr против NULL. Ничего внятного (для простых инженеров, а не всяких там страуструпов) не нашел, кроме синтетического примера

void foo(int *) < coutvoid foo(int) < coutfoo(NULL); foo(nullptr); 
foo(int) foo(int *) 

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

da17 ★
28.01.19 13:25:53 MSK

Но этого что-то мало и вроде я такое раз в год вызываю

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

seiken ★★★★★
( 28.01.19 13:44:42 MSK )
Ответ на: комментарий от seiken 28.01.19 13:44:42 MSK

Так из-за этого и спрашиваю, где это используется?

da17 ★
( 28.01.19 13:51:37 MSK ) автор топика

у меня твой пример не компилируется.

 error: call of overloaded ‘foo(NULL)’ is ambiguous

conalex ★★★
( 28.01.19 13:57:09 MSK )
Ответ на: комментарий от conalex 28.01.19 13:57:09 MSK

MSVC 2013 собирал, там норм прошло

da17 ★
( 28.01.19 14:16:43 MSK ) автор топика
Ответ на: комментарий от da17 28.01.19 13:51:37 MSK

NULL это просто 0, ещё и определённый макросом, т.е. компилятор получит просто 0 в этом куске кода, некоторые конструкции аля auto не поймут что именно ты хотел использовать число или указатель

sparks ★★★
( 28.01.19 14:33:13 MSK )

Effective Modern C++ Майерса.
Item 8: Prefer nullptr to 0 and NULL.

Показано развитие приведённого тобою примера для случая когда такие перегрузки за шаблонами скрыты.

mkam ★
( 28.01.19 14:36:12 MSK )

nullptr нельзя по ошибке присвоить переменной, не являющейся указателем, с NULL такое скомпилируется и может потом привести к многочасовой отладке

annulen ★★★★★
( 28.01.19 14:40:07 MSK )
Ответ на: комментарий от annulen 28.01.19 14:40:07 MSK
da17 ★
( 28.01.19 15:08:26 MSK ) автор топика

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

Если же тебе неймётся, все ответы есть на cppreference. NULL - это implementation-defined макрос который может в зависимости от реализации раскрываться в 0 или nullptr, поэтому вопрос сводится к тому почему нельзя использовать 0 (или, что эквивалентно, макрос который может в него раскрыться). Потому что это нарушает типобезопасность - 0 можно передать в функцию принимающую int, или сравнить с int’ом. Если ты сравниваешь NULL с int’ом, или передаёшь в качестве int’а - это явная ошибка, но в этом случае компилятор её не отловит. У nullptr таких проблем нет. Кроме того, он может участвовать в перегрузках (https://en.cppreference.com/w/cpp/types/nullptr_t).

slovazap ★★★★★
( 28.01.19 15:09:25 MSK )
Ответ на: комментарий от da17 28.01.19 15:08:26 MSK

void f(int a); f(nullptr); // error 

annulen ★★★★★
( 28.01.19 15:14:36 MSK )
Ответ на: комментарий от slovazap 28.01.19 15:09:25 MSK

сравниваю NULL с int

#include #include class Keker< >; int main()

Компилятор ругается In function 'int main()': 12:16: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]

da17 ★
( 28.01.19 15:16:36 MSK ) автор топика

Дальше не читал

Gvidon ★★★★
( 28.01.19 15:19:10 MSK )
Ответ на: комментарий от Gvidon 28.01.19 15:19:10 MSK

Я прочитал пример https://en.cppreference.com/w/cpp/types/nullptr_t т.е. если я все правильно понял, nullptr помогает явно указать, что должна вызываться ф-ия принимающая указатель и если у программиста функция, принимающая foo(int), а он где-то в дебрях кода передает ей нулевой указатель путем foo(NULL), то возможно он ошибся и nullptr от таких косяков уберегает, т.е. если даже программист забудет, чего принимает ф-ия, компилятор его поправит при nullptr, чего не будет при NULL?

da17 ★
( 28.01.19 15:30:21 MSK ) автор топика
Ответ на: комментарий от Gvidon 28.01.19 15:19:10 MSK

да я пошутил, а то иногда напишут вместо пояснения «НАРУШАЕТ ПРИНЦИПЫ ООП» и гадай, что оно там нарушает

da17 ★
( 28.01.19 15:32:18 MSK ) автор топика

История примерно такая:
1) В С++ запретили неявное приведение void* к любому другому указателю, что в С разрешено. Внезапно, отломался код

int* foo = NULL; 

т.к. NULL всегда определялся как (void*)0.
2) Не унывая, в С++ решили эту проблему переиспользованием константы 0, что привело к вот такой вот радости (примерно):

#ifdef __cplusplus #define NULL 0 #else #define NULL (void*)0 #endif 

Что, в свою очередь, начало весело стрелять при перегрузках и в шаблонах.
3) Компиляторы от такой весёлой жизни начали заводить свои нестандартные «нулевые указатели», чтобы с этим адом хоть как-то бороться. Например __null в gcc.
4) Пункт 3) узаконили в стандарте как nullptr

Всё это время сишники смотрят на плюсовиков как на стадо дебилов, пишут свой родной NULL и в ус не дуют.

Gvidon ★★★★
( 28.01.19 15:59:55 MSK )
Ответ на: комментарий от da17 28.01.19 15:16:36 MSK

И что вы хотели сказать этим примером? К NULL vs. nullptr он вообще никакого отношения не имеет.

slovazap ★★★★★
( 28.01.19 16:32:37 MSK )

В чистом Си у тебя ведь перегрузки функций нет? Вот там это в ногу не выстрелит. А в костылях выстрелит и будет неприятно.

Вот и пиши nullptr , чтобы избежать двусмысленности.

Deleted
( 28.01.19 16:41:55 MSK )
Ответ на: комментарий от da17 28.01.19 15:08:26 MSK

Например такой: #include

int main() < char str[] = "hello"; char* p = str; /* что-то делаем со строкой */ p = 0; >

То есть мы работаем со строкой, теперь захотели ограничить строку на текущем символе, и вместо

*p = '\0'; 

написали просто

p = 0; 

Какой-то пример с массивом строк и присваиванием нуля, вместо '\0', был в одном из разборов PVS-studio какого-то опенсурс проекта, так что несмотря на то что пример искусственный, что-то подобное есть и в реальных проектах.

Но в gcc/clang есть полезное предупреждение

-Wzero-as-null-pointer-constant 

Чем отличается null от nullptr

Здравствуйте, N. I., Вы писали:

NI>Это не баг, а вполне себе правильное для C++98 — C++11 поведение.

для С++14 это вроде баг
решил на уровне стандарта найти разницу, вроде нашел:

4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to
zero
or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the
result is the null pointer value of that type and is distinguishable from every other value of pointer to object
or pointer to function type. Two null pointer values of the same type shall compare equal. The conversion
of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a
pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can
be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value.
—end note ]

4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t.
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type
and is distinguishable from every other value of object pointer or function pointer type. Such a conversion
is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The
conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the
sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of
integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a
null pointer value. —end note ]

NI>void* может быть в C, но не в C++.
хотел подчеркнуть, что стандартом не регламентируется какого типа NULL. вроде зафиксировано, что это макрос, но в доках не нашел =\

Отредактировано 01.12.2016 13:12 uzhas . Предыдущая версия . Еще …
Отредактировано 01.12.2016 13:11 uzhas . Предыдущая версия .
Re: 0 vs NULL vs nullptr

От: uzhas
Дата: 01.12.16 11:41
Оценка: 4 (1) +1

Здравствуйте, RiNSpy, Вы писали:

RNS>Выходит, просто 0 или NULL компилятор может сконверитировать в указатель; (int)0 и (int)NULL тоже может.
эти два выражения не должны конвертироваться в указатель. у них тип int

RNS>Но если 0 или NULL передаются как параметр функции типа int, то компилятор уже не может превратить их в указатель? В чём разница?

литеральный 0 может преобразовываться в указатель. за это отвечает не система типов, а компилятор. то есть он видит литеральный ноль + видит передачу указателя -> он передает нулевой указатель
в других ситуациях 0 является константой с типом int
варианты из вашего примера, которые также не должны компилироваться:

std::cout<int)0)int)NULL)

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

NULL — это некоторая константа, которая умеет преобразовываться к нулевому указателю. ее тип — implementation defined. бывает int (литеральный 0), а бывает void*

собственно, чтобы немного уменьшить кол-во зоопарка и ввели nullptr, у которого есть даже свой тип — nullptr_t

в этих двух примерах

RNS> //std::cout <RNS> //std::cout<

NULL == nullptr в C++11?

не совcем. NULL большинством компиляторов с легкостью трактуется как 0 (на самом деле это обычно define). Но нет 100 гарантии, что это так. А вот nullptr - это известная для компилятора константа и компилятор знает, что это такое.

6 дек 2013 в 13:29

@KoVadim, можно сказать, что надежнее будет инициализировать указатели nullptr, для дальнейшей проверки на корректность, нежели NULL?

6 дек 2013 в 13:58

nullptr как раз специально ввели, что бы решить часть неоднозначных ситуаций с NULL. Это все лучше утрясется в голове, если понимать, то компилятор не видет NULL, он видит обычно вместо него 0 (препроцессор постарался). А вот nullptr виден. И компилятор может сделать анализ.

6 дек 2013 в 14:43

@SoloMio, не совсем. Везде где идет речь про указатели НУЖНО использовать null_ptr. Это гарантия того, что компилятор попробует застраховать программиста от ошибки.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

https://czena.narkolog-na-dom-voronezh-11.ru/