Чем отличается null от nullptr
Перейти к содержимому

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

  • автор:

NULL and nullptr comparison

Is it safe to compare pointers where one is NULL and other is nullptr? Will that comparison always give true?

38k 25 25 gold badges 201 201 silver badges 273 273 bronze badges
asked Dec 4, 2015 at 22:41
wieczorekm wieczorekm
158 2 2 silver badges 9 9 bronze badges

2 Answers 2

Both NULL and nullptr are «null pointer constants» and

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.

Two null pointer values of the same type shall compare equal.

(Both quotes 4.10/1 in N4140)

answered Dec 4, 2015 at 22:51
Baum mit Augen ♦ Baum mit Augen
49.5k 25 25 gold badges 146 146 silver badges 184 184 bronze badges
Just to remind that there is only one «nullptr» shared by all pointer types.
Apr 26, 2019 at 14:56

If I compare (nullptr == NULL) I get error: comparison between NULL and non-pointer (‘std::nullptr_t’ and NULL) [-Werror,-Wnull-arithmetic] in clang ☹

Oct 7, 2023 at 0:40

@mirabilos That is comparing the NULL literal to nullptr , which is different to the scenario discussed here: comparing two pointers where one has been assigned NULL and the other nullptr . The important difference is that NULL is usually not a pointer in C++.

Oct 14, 2023 at 21:07

@BaummitAugen but the compiler complains not about NULL not being a pointer but about nullptr not being one. (But someone on Fedi helped me, casting either one to void * fixes that.)

Oct 17, 2023 at 23:24

@mirabilos Sure, this question is about comparing pointers, your scenario is comparing null pointer constants. As you have discovered, null pointer constants are not pointers, so this answer doesn’t apply to your scenario. By casting at least one of the null pointer constants to pointer, you change your scenario to the pointer comparison.

What is the nullptr keyword, and why is it better than NULL?

We now have C++11 with many new features. An interesting and confusing one (at least for me) is the new nullptr . Well, no need anymore for the nasty macro NULL .

int* x = nullptr; myclass* obj = nullptr; 

Still, I am not getting how nullptr works. For example, Wikipedia article says:

C++11 corrects this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. It is not implicitly convertible or comparable to integral types, except for bool.

How is it a keyword and an instance of a type? Also, do you have another example (beside the Wikipedia one) where nullptr is superior to good old 0 ?

30.6k 8 8 gold badges 73 73 silver badges 137 137 bronze badges
asked Aug 15, 2009 at 16:47
Khaled Alshaya Khaled Alshaya
95.7k 41 41 gold badges 178 178 silver badges 236 236 bronze badges
related fact: nullptr is also used to represent null reference for managed handles in C++/CLI.
Aug 15, 2009 at 16:52

Is nullptr_t guaranteed to have only one member, nullptr ? So, if a function returned nullptr_t , then the compiler already knows which value will be returned, regardless of the body of the function?

Jul 28, 2015 at 11:02

@AaronMcDaid std::nullptr_t can be instantiated, but all instances will be identical to nullptr because the type is defined as typedef decltype(nullptr) nullptr_t . I believe the primary reason the type exists is so that functions can be overloaded specifically to catch nullptr , if necessary. See here for an example.

Jun 14, 2016 at 23:26

0 never was a null pointer, null pointer is a pointer that can be get by casting zero literal to pointer type, and it doesn’t point to any existing object by definition.

Mar 6, 2017 at 7:26
@Nils The point is expressing intent!
Jul 8, 2019 at 1:06

14 Answers 14

How is it a keyword and an instance of a type?

This isn’t surprising. Both true and false are keywords and as literals they have a type ( bool ). nullptr is a pointer literal of type std::nullptr_t , and it’s a prvalue (you cannot take the address of it using & ).

  • 4.10 about pointer conversion says that a prvalue of type std::nullptr_t is a null pointer constant, and that an integral null pointer constant can be converted to std::nullptr_t . The opposite direction is not allowed. This allows overloading a function for both pointers and integers, and passing nullptr to select the pointer version. Passing NULL or 0 would confusingly select the int version.
  • A cast of nullptr_t to an integral type needs a reinterpret_cast , and has the same semantics as a cast of (void*)0 to an integral type (mapping implementation defined). A reinterpret_cast cannot convert nullptr_t to any pointer type. Rely on the implicit conversion if possible or use static_cast .
  • The Standard requires that sizeof(nullptr_t) be sizeof(void*) .

40.2k 11 11 gold badges 101 101 silver badges 144 144 bronze badges
answered Aug 15, 2009 at 17:06
Johannes Schaub — litb Johannes Schaub — litb
502k 131 131 gold badges 908 908 silver badges 1.2k 1.2k bronze badges

Oh, after looking, it seems to me that the conditional operator can’t convert 0 to nullptr in cases like cond ? nullptr : 0; . Removed from my answer.

Aug 15, 2009 at 17:23

Note that NULL is not even guaranteed to be 0 . It can be 0L , in which case a call to void f(int); void f(char *); will be ambiguous. nullptr will always favor the pointer version, and never call the int one. Also note that nullptr is convertible to bool (the draft says that at 4.12 ).

Aug 15, 2009 at 18:09
@litb: so regarding f(int) and f(void*) — will f(0) still be ambiguous?
Aug 15, 2009 at 20:48

@Steve, no that will call the int version. But f(0L) is ambiguous, because long -> int aswell as long -> void* is both equally costly. So if NULL is 0L on your compiler, then a call f(NULL) will be ambiguous given those two functions. Not so with nullptr of course.

Aug 15, 2009 at 22:14

@SvenS It must not be defined as (void*)0 in C++. But it can be defined as any arbitrary null pointer constant, which any integral constant with value 0 and nullptr fulfill. So, most definitely not will but can. (You forgot to ping me btw..)

Feb 24, 2016 at 1:31

Why nullptr in C++11? What is it? Why is NULL not sufficient?

C++ expert Alex Allain says it perfectly here (my emphasis added in bold):

. imagine you have the following two function declarations:

void func(int n); void func(char *s); func( NULL ); // guess which function gets called? 

Although it looks like the second function will be called—you are, after all, passing in what seems to be a pointer—it’s really the first function that will be called! The trouble is that because NULL is 0, and 0 is an integer, the first version of func will be called instead. This is the kind of thing that, yes, doesn’t happen all the time, but when it does happen, is extremely frustrating and confusing. If you didn’t know the details of what is going on, it might well look like a compiler bug. A language feature that looks like a compiler bug is, well, not something you want.

Enter nullptr. In C++11, nullptr is a new keyword that can (and should!) be used to represent NULL pointers; in other words, wherever you were writing NULL before, you should use nullptr instead. It’s no more clear to you, the programmer, (everyone knows what NULL means), but it’s more explicit to the compiler, which will no longer see 0s everywhere being used to have special meaning when used as a pointer.

Allain ends his article with:

Regardless of all this—the rule of thumb for C++11 is simply to start using nullptr whenever you would have otherwise used NULL in the past.

Lastly, don’t forget that nullptr is an object—a class. It can be used anywhere NULL was used before, but if you need its type for some reason, it’s type can be extracted with decltype(nullptr) , or directly described as std::nullptr_t , which is simply a typedef of decltype(nullptr) , as shown here:

Defined in header :

  1. https://en.cppreference.com/w/cpp/types/nullptr_t
  2. and https://en.cppreference.com/w/cpp/header/cstddef
namespace std < typedef decltype(nullptr) nullptr_t; // (since C++11) // OR (same thing, but using the C++ keyword `using` instead of the C and C++ // keyword `typedef`): using nullptr_t = decltype(nullptr); // (since C++11) >// namespace std 

References:

  1. Cprogramming.com: Better types in C++11 — nullptr, enum classes (strongly typed enumerations) and cstdint
  2. https://en.cppreference.com/w/cpp/language/decltype
  3. https://en.cppreference.com/w/cpp/types/nullptr_t
  4. https://en.cppreference.com/w/cpp/header/cstddef
  5. https://en.cppreference.com/w/cpp/keyword/using
  6. https://en.cppreference.com/w/cpp/keyword/typedef

answered Mar 7, 2018 at 6:18
Gabriel Staples Gabriel Staples
45k 20 20 gold badges 234 234 silver badges 317 317 bronze badges

The new C++09 nullptr keyword designates an rvalue constant that serves as a universal null pointer literal, replacing the buggy and weakly-typed literal 0 and the infamous NULL macro. nullptr thus puts an end to more than 30 years of embarrassment, ambiguity, and bugs. The following sections present the nullptr facility and show how it can remedy the ailments of NULL and 0.

  • WikiBooks, with sample code.
  • Here at Stack Overflow: Do you use NULL or 0 (zero) for pointers in C++?
  • template
  • Google group: comp.lang.c++.moderated — compiler discussion

1 1 1 silver badge
answered Aug 15, 2009 at 17:02
13.4k 3 3 gold badges 42 42 silver badges 57 57 bronze badges
C++09? Wasn’t it referred to as C++0x before Aug 2011?
Mar 12, 2013 at 19:10

@anthropomorphic Well that’s its purpose. C++0x was used while it was still work in progress, because it wasn’t known whether it would be finished 2008 or 2009. Note that it actually became C++0B meaning C++11. See stroustrup.com/C++11FAQ.html

Apr 14, 2016 at 9:59

When you have a function that can receive pointers to more than one type, calling it with NULL is ambiguous. The way this is worked around now is very hacky by accepting an int and assuming it’s NULL .

template class ptr < T* p_; public: ptr(T* p) : p_(p) <>template ptr(U* u) : p_(dynamic_cast(u)) < >// Without this ptr p(NULL) would be ambiguous ptr(int null) : p_(NULL) < assert(null == NULL); >>; 

In C++11 you would be able to overload on nullptr_t so that ptr p(42); would be a compile-time error rather than a run-time assert .

ptr(std::nullptr_t) : p_(nullptr)

answered Aug 16, 2009 at 6:46
113k 52 52 gold badges 192 192 silver badges 265 265 bronze badges
What if NULL is defined as 0L ?
May 4, 2019 at 7:49

nullptr can’t be assigned to an integral type such as an int but only a pointer type; either a built-in pointer type such as int *ptr or a smart pointer such as std::shared_ptr

I believe this is an important distinction because NULL can still be assigned to both an integral type and a pointer as NULL is a macro expanded to 0 which can serve as both an initial value for an int as well as a pointer.

20.1k 8 8 gold badges 51 51 silver badges 83 83 bronze badges
answered Jan 29, 2013 at 13:12
user633658 user633658
2,563 2 2 gold badges 18 18 silver badges 16 16 bronze badges
Note that this answer is wrong. NULL is not guaranteed to be expanded to 0 .
Jul 4, 2019 at 7:26

Also, do you have another example (beside the Wikipedia one) where nullptr is superior to good old 0?

Yes. It’s also a (simplified) real-world example that occurred in our production code. It only stood out because gcc was able to issue a warning when crosscompiling to a platform with different register width (still not sure exactly why only when crosscompiling from x86_64 to x86, warns warning: converting to non-pointer type ‘int’ from NULL ):

Consider this code (C++03):

#include struct B <>; struct A < operator B*() operator bool() >; int main() < A a; B* pb = 0; typedef void* null_ptr_t; null_ptr_t null = 0; std::cout 

It yields this output:

(a == pb): 1 (a == 0): 0 (a == NULL): 0 (a == null): 1 

10.9k 8 8 gold badges 60 60 silver badges 103 103 bronze badges
answered Sep 25, 2013 at 20:31
Gabriel Schreiber Gabriel Schreiber
2,206 1 1 gold badge 21 21 silver badges 33 33 bronze badges

I fail to see how this improves when using nullptr (and C++11). If you set pb to nullptr the first comparison evaluates still true (while comparing apples with pears..). The second case is even worse: If you compare a to nullptr it will convert a to B* and then it will evaluate to true again (before it was casted to bool and the expr evaluated to false). The whole thingy reminds me of JavaScript and I wonder if we will get === in C++ in the future 🙁

Apr 25, 2018 at 11:01

Well, other languages have reserved words that are instances of types. Python, for instance:

>>> None = 5 File "", line 1 SyntaxError: assignment to None >>> type(None)

This is actually a fairly close comparison because None is typically used for something that hasn't been intialized, but at the same time comparisons such as None == 0 are false.

On the other hand, in plain C, NULL == 0 would return true IIRC because NULL is just a macro returning 0, which is always an invalid address (AFAIK).

answered Aug 15, 2009 at 16:52
Mark Rushakoff Mark Rushakoff
254k 46 46 gold badges 409 409 silver badges 400 400 bronze badges

NULL is a macro that expands to a zero, a constant zero cast to a pointer produces a null pointer. A null pointer doesn't have to be zero (but often is), zero isn't always an invalid address, and a non-constant zero cast to a pointer doesn't have to be null, and a null pointer cast to an integer doesn't have to be zero. I hope I got that all right without forgetting anything. A reference: c-faq.com/null/null2.html

Mar 2, 2013 at 1:19

Let me first give you an implementation of unsophisticated nullptr_t

struct nullptr_t < void operator&() const = delete; // Can't take address of nullptr templateinline operator T*() const < return 0; >template inline operator T C::*() const < return 0; >>; nullptr_t nullptr; 

nullptr is a subtle example of Return Type Resolver idiom to automatically deduce a null pointer of the correct type depending upon the type of the instance it is assigning to.

int *ptr = nullptr; // OK void (C::*method_ptr)() = nullptr; // OK 
  • As you can above, when nullptr is being assigned to an integer pointer, a int type instantiation of the templatized conversion function is created. And same goes for method pointers too.
  • This way by leveraging template functionality, we are actually creating the appropriate type of null pointer every time we do, a new type assignment.
  • As nullptr is an integer literal with value zero, you can not able to use its address which we accomplished by deleting & operator.

Why do we need nullptr in the first place?

  • You see traditional NULL has some issue with it as below:

1️⃣ Implicit conversion

char *str = NULL; // Implicit conversion from void * to char * int i = NULL; // OK, but `i` is not pointer type 

2️⃣ Function calling ambiguity

void func(int) <> void func(int*)<> void func(bool)<> func(NULL); // Which one to call? 
  • Compilation produces the following error:
error: call to 'func' is ambiguous func(NULL); ^~~~ note: candidate function void func(bool)<> ^ note: candidate function void func(int*)<> ^ note: candidate function void func(int)<> ^ 1 error generated. compiler exit status 1 

3️⃣ Constructor overload

struct String < String(uint32_t) < /* size of string */ >String(const char*) < /* string */ >>; String s1( NULL ); String s2( 5 ); 
  • In such cases, you need explicit cast (i.e., String s((char*)0)) .

3,136 6 6 gold badges 9 9 silver badges 28 28 bronze badges
answered Apr 13, 2020 at 3:36
Vishal Chovatiya Vishal Chovatiya
99 1 1 silver badge 4 4 bronze badges

It is a keyword because the standard will specify it as such. 😉 According to the latest public draft (n2914)

pointer-literal: nullptr 

The pointer literal is the keyword nullptr . It is an rvalue of type std::nullptr_t .

It's useful because it does not implicitly convert to an integral value.

1 1 1 silver badge
answered Aug 15, 2009 at 17:00
8,997 5 5 gold badges 34 34 silver badges 38 38 bronze badges

Let's say that you have a function (f) which is overloaded to take both int and char*. Before C++ 11, If you wanted to call it with a null pointer, and you used NULL (i.e. the value 0), then you would call the one overloaded for int:

void f(int); void f(char*); void g() < f(0); // Calls f(int). f(NULL); // Equals to f(0). Calls f(int). >

This is probably not what you wanted. C++11 solves this with nullptr; Now you can write the following:

void g() < f(nullptr); //calls f(char*) >

answered Oct 20, 2017 at 21:14
2,614 2 2 gold badges 23 23 silver badges 30 30 bronze badges

0 used to be the only integer value that could be used as a cast-free initializer for pointers: you can not initialize pointers with other integer values without a cast. You can consider 0 as a consexpr singleton syntactically similar to an integer literal. It can initiate any pointer or integer. But surprisingly, you'll find that it has no distinct type: it is an int . So how come 0 can initialize pointers and 1 cannot? A practical answer was we need a means of defining pointer null value and direct implicit conversion of int to a pointer is error-prone. Thus 0 became a real freak weirdo beast out of the prehistoric era. nullptr was proposed to be a real singleton constexpr representation of null value to initialize pointers. It can not be used to directly initialize integers and eliminates ambiguities involved with defining NULL in terms of 0. nullptr could be defined as a library using std syntax but semantically looked to be a missing core component. NULL is now deprecated in favor of nullptr , unless some library decides to define it as nullptr .

506 6 6 silver badges 12 12 bronze badges
answered Jun 16, 2018 at 7:33
3,297 12 12 silver badges 19 19 bronze badges

Here's the LLVM header.

// -*- C++ -*- //===--------------------------- __nullptr --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef _LIBCPP_NULLPTR #define _LIBCPP_NULLPTR #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif #ifdef _LIBCPP_HAS_NO_NULLPTR _LIBCPP_BEGIN_NAMESPACE_STD struct _LIBCPP_TEMPLATE_VIS nullptr_t < void* __lx; struct __nat ; _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t() : __lx(0) <> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t(int __nat::*) : __lx(0) <> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator int __nat::*() const template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator _Tp* () const template _LIBCPP_INLINE_VISIBILITY operator _Tp _Up::* () const friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator==(nullptr_t, nullptr_t) friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, nullptr_t) >; inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t __get_nullptr_t() #define nullptr _VSTD::__get_nullptr_t() _LIBCPP_END_NAMESPACE_STD #else // _LIBCPP_HAS_NO_NULLPTR namespace std < typedef decltype(nullptr) nullptr_t; >#endif // _LIBCPP_HAS_NO_NULLPTR #endif // _LIBCPP_NULLPTR 

(a great deal can be uncovered with a quick grep -r /usr/include/*` )

One thing that jumps out is the operator * overload (returning 0 is a lot friendlier than segfaulting. ). Another thing is it doesn't look compatible with storing an address at all. Which, compared to how it goes slinging void*'s and passing NULL results to normal pointers as sentinel values, would obviously reduce the "never forget, it might be a bomb" factor.

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

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