In C and C++ we use the preprocessor macro NULL to say a pointer is not pointing to anywhere right now.
The problem with NULL is that underneath it is just a plain 0.
Consider the problem looking at this code excerpt:
#include <iostream> using namespace std; void m(int x) { cout << x << endl; } void m(const char* x) { cout << (x == NULL ? "NULL" : x) << endl; } int main() { m(12); m(NULL); return 0; }
If you try to compile it using g++ 4.6, you will get something like:
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 nullptr
; a keyword that unambiguously represents a pointer pointing to nowhere; no 0 at all.
Pros:
- It is a strongly typed null pointer, like Java or C# null.
- No ambiguity when trying to pass a null pointer to something accepting an int.
- It is a keyword, so you cannot define it to whatever you want.
Cons:
- If you have some symbol called nullptr used in a lot of places in your code, you will need to edit your source code to rename it.
So, if you change the main method of my example above to:
int main() { m(12); m(nullptr); return 0; }
Your code will compile and execute with no problems.
As Joe noted in his comment on this post (thanks Joe!), the type of nullptr
is actually nullptr_t
, so, you would be also able to overload the m()
function to perform different if the argument is nullptr
, as shown in this example below:
void m(int x) { cout << x << endl; } void m(const char* x) { cout << x << endl; } void m(nullptr_t) { cout << "nullptr!" << endl; } int main() { m(12); m(nullptr); return 0; }
The type of nullptr is nullptr_t, and you can overload on it. This is most useful when you have a function f that is overloaded on two or more pointer types so that f(nullptr) is ambiguous. If you also overload f on nullptr_t, then f(nullptr) will always call f(nullptr_t).
Thanks Joe, I updated this post adding what you stated.
It’s been a long time, but I feel obliged to point out a minor mistake: in both 2003 and 2011 Standard versions NULL is implementation-defined, but a footnote explicitly forbids “(void*)0” definition.
That’s not surprising, should NULL be defined as (void*)0, code like
Foo* foo = NULL;
would be ill-formed, since void* in C++ (in contrast to C) is not implicitly convertible to other pointer types. Same footnote mentiones “0” and “0L” as viable options.
(Note that the example program could be well-formed if NULL was defined as 0)
Hope it doesn’t sound negative – I consider your articles a nice introduction to C++11 features :)
Thanks for clarifying!!! I’m updating my article accordingly! :) Thanks for reading me.
Cloooose, but not perfect :) If NULL was a plain zero, f(int) overload would be choosen, since it’s an exact match, while f(char*) requires pointer conversion, which is strictly worse match wrt overload resolution rules. You can easily check it by calling f(0). As of gcc 4.7.1, NULL seems to be defined as “__null”, which looks like a special internal symbol (especially since “NULL” appears unchanged in the diagnostics). Haven’t checked, but I bet it’s the same in many if not all previous releases.
I promise to refrain from further harrasment :D