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.

 

2 Comments


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

    Reply
    • Marco Foco

      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.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.