A nullptr
is a representation of the null pointer that implicitly converts into any pointer type, but not into an integral type.
nullptr
, and its type nullptr_t
, have been standardised in C++11, but its introduction predates the standard by at least 15 years, since the idea is contained in Scott Meyer‘s book Effective C++, 2nd edition, published in 1996.
Despite being a rather old idea, being in the standard for five years, being available in the compilers since even longer and having a quite straightforward fallback implementation, I still see a lot of new code using 0
, or worse, NULL
to represent null pointers.
Look at the “historical” test to show the reasons behind the creation of nullptr
:
void a(int x) { cout << "int" << endl; } void a(void *y) { cout << "pointer" << endl; } int main() { a(0); // int overload a((void*)0); // void * overload a(nullptr); // void * overload a(NULL); // ??? }
This examples shows that if, during a refactoring, you decide to pass a 0
(instead of a pointer) to your function a
, you will end up calling a completely different overload, because no conversion is preferable to implicit conversion of a 0
into a void*
, and this generates a silent bug. If you want to be sure to use the right overload, you have to explicitly cast your 0
to the right pointer type (in this case, a void*
)
nullptr
doesn’t suffer of this problem, since it’s a different type (std::nullptr_t
), an implicit conversion will take place anyway (and a better overload would be one taking an std::nullptr_t
type as parameter).
But wait, why those question marks when using NULL
? Why NULL
should be worse than 0
?
Well, to my surprise, when testing this I got an error (clang 3.7-based Apple compiler):
error: call to 'a' is ambiguous
What ambiguity was the compiler complaining about? Well, apparently NULL
in clang is defined as 0L
, so both the int
and void*
overload require exactly one implicit conversion to be selected.
On Visual Studio 2015, on the other hand, the above code compiles and matches the int
overload, because it’s defined as a plain 0
, but would complain with a long
overload.
As I said, this doesn’t happen with nullptr
, because in normal circumstances you don’t need to write an overload to handle std::nullptr_t
, so nullptr
s are always implicitly converted into pointer types: ambiguity will only rise if you have your function overloaded on different pointer types, but that will generate a compile-time error, and not a silent bug.
#
Hi,
only out of curiosity. Here is your article in german. It’s from the 9th of January.
http://www.grimm-jaud.de/index.php/blog/die-null-zeiger-konstante-nullptr
Rainer
#
Hi Rainer,
I can’t read German, but from what google translate provided me, looks like I came up with the same idea you had few days ago.
Interesting :)
From what I get, your article seem to explore the problem more in depth, so if you agree I’ll modify my article and add a link at the end of mine, so German-speaking readers can read your article too.