According to cppreference, nullptr is a keyword that:
denotes the pointer literal. It is a prvalue of type std::nullptr_t. There exist implicit conversions from nullptr to null pointer value of any pointer type and any pointer to member type. Similar conversions exist for any null pointer constant, which includes values of type std::nullptr_t as well as the macro NULL.
So nullptr is a value of a distinct type std::nullptr_t, not int. It implicitly converts to the null pointer value of any pointer type. This magic happens under the hood for you and you don't have to worry about its implementation. NULL, however, is a macro and it is an implementation-defined null pointer constant. It's often defined like this:
#define NULL 0
i.e. an integer.
This is a subtle but important difference, which can avoid ambiguity.
For example:
int i = NULL; //OK int i = nullptr; //error int* p = NULL; //OK int* p = nullptr; //OK
and when you have two function overloads like this:
void func(int x); //1) void func(int* x); //2)
func(NULL) calls 1) because NULL is an integer. func(nullptr) calls 2) because nullptr converts implicitly to a pointer of type int*.
Also if you see a statement like this:
auto result = findRecord( /* arguments */ ); if (result == nullptr) { ... }
and you can't easily find out what findRecord returns, you can be sure that result must be a pointer type; nullptr makes this more readable.
In a deduced context, things work a little differently. If you have a template function like this:
template<typename T> void func(T *ptr) { ... }
and you try to call it with nullptr:
func(nullptr);
you will get a compiler error because nullptr is of type nullptr_t. You would have to either explicitly cast nullptr to a specific pointer type or provide an overload/specialization for func with nullptr_t.
Advantages of using nulptr:
- avoid ambiguity between function overloads
- enables you to do template specialization
- more secure, intuitive and expressive code, e.g.
if (ptr == nullptr) instead of if (ptr == 0)
nullptris also used to represent null reference for managed handles in C++/CLI.nullptr_tguaranteed to have only one member,nullptr? So, if a function returnednullptr_t, then the compiler already knows which value will be returned, regardless of the body of the function?std::nullptr_tcan be instantiated, but all instances will be identical tonullptrbecause the type is defined astypedef decltype(nullptr) nullptr_t. I believe the primary reason the type exists is so that functions can be overloaded specifically to catchnullptr, if necessary. See here for an example.