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 nullptrs 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.