In C and C++, the preprocessor definition NULL is/was used to explicitly indicate that a pointer is not pointing anywhere right now.
The problem with NULL is that underneath it is just a plain 0, something like this:
#define NULL 0
The following code excerpt shows how this can turn into a problem:
#include <iostream>
void m(int x)
{
std::cout << x << endl;
}
void m(const char* x)
{
std::cout << (x == NULL ? "NULL" : x) << std::endl;
}
int main()
{
m(12);
m(NULL);
return 0;
}
When that code is compiled, the following error is displayed:
test.cpp: In function 'int main()':
test.cpp:19:9: error: call of overloaded 'm(NULL)' is ambiguous
test.cpp:19:9: note: candidates are:
test.cpp:5:6: note: void m(int)
test.cpp:10:6: note: void m(const char*)
Why does the compiler consider the m(NULL) ambiguous?
Because it cannot decide if NULL is actually a pointer (because it is a 0) or an integer (because NULL is… a 0).
C++11 introduces the literal nullptr of type std::nullptr_t; a literal that unambiguously represents a pointer pointing nowhere, eliminating the concept of being a pointer pointing to memory address 0.
It has these advantages:
- It is a strongly typed null pointer, like Java or C#
null. - No ambiguity when trying to pass a null pointer to something accepting, say, an
int. - It is a literal and a keyword, so it cannot be defined or used as a symbolic name.
- It cannot be casted automatically to a numeric type, as
NULLcan.
So, if the example above is replaced with this construction, there is this code:
int main()
{
m(12);
m(nullptr);
return 0;
}
The code will compile and execute with no problems.
Since the type of nullptr is std::nullptr_t, which is a native type, programmers can also write a specific overload when the nullptr literal is passed as a parameter, as in the following example:
void m(int x)
{
std::cout << x << std::endl;
}
void m(const char* x)
{
std::cout << x << std::endl;
}
void m(nullptr_t)
{
std::cout << "nullptr!" << std::endl;
}
int main()
{
m(12);
m(nullptr);
return 0;
}