nullptr: A Type-safe and Clear-Cut Null Pointer

he new C++09 nullptr keyword designates an rvalue constant that serves as a universal null pointer literal, replacing the buggy and weakly-typed literal 0 and the infamous NULL macro. nullptr thus puts an end to more than 30 years of embarrassment, ambiguity, and bugs. The following sections present the nullptr facility and show how it can remedy the ailments of NULL and 0.

The literal 0 (which is essentially of type int) also serves as a null pointer literal in C++. This kludge results in ambiguity and bugs.

Use the nullptr keyword instead of 0 to indicate a null pointer value.

Presenting the Problem
In C++, the macro NULL is a synonym for the literal 0. For this reason, most C++ programs use 0 directly to initialize, assign, and compare null pointers. Whether you’re using NULL or 0, your C++ apps are subjected to bugs and maintenance problems that are caused by the ambiguity of 0. Consider these two overloaded versions of a function called func:

void func(int);void func (char *);int main(){ func(0); //which func is called?}

The function call func(0) is always resolved as func(int), never as func(char *)?even if you meant to call the latter with a null pointer argument! To call the latter, you must use an explicit cast expression:

func( (char *)0); //ugly but unavoidable

Most C++ programmers aren’t aware of this trap; they mistakenly assume that passing NULL as the argument of func will invoke the char* overload:

func(NULL); //still calls func(int)

Remember: In C++, NULL is a synonym for the literal 0. It’s never implemented as void* because NULL must also be compatible with pointers to members:

struct A {/**/};int (A::*pmf)(char *)=NULL;

However, there is a subtler problem involving NULL and 0. When you modify a large corpus of code automatically (by using search and replace or a script), it’s very difficult to distinguish between code statements in which 0 stands for a numeric value and statements that use 0 as a null pointer. Using NULL is only a partial solution because NULL is replaced with the literal 0 during the preprocessing stage. Furthermore, you have to #include a standard header file in order to use NULL. What you want is a strongly-typed, built-in keyword whose meaning is unambiguous and explicit. This is exactly what nullptr is.

nullptr is a reserved keyword designating an rvalue constant of type std::nullptr_t. The underlying type of std::nullptr_t is implementation-defined. However, it must be a POD type, whose size is the same as sizeof(void*). nullptr is implicitly converted to pointers and pointers to members. However, nullptr is not convertible to bool or any of the numeric types of C++:

//pointers and numeric typeschar *pc=nullptr; //OKchar c=nullptr; //error, type mismatchint num=nullptr; //error, type mismatch//pointers to membersint (A::*pmf)(char *)=nullptr; //OKint A::*pmi=nullptr; //OK, pointer to data member //comparisonsif (nullptr==0) //error, type mismatchif (nullptr)//error, conversion to bool not allowedif (pc==nullptr) //OK

See how nullptr elegantly solves the overload resolution problem shown earlier:

void func(int);void func(char *);int main(){ func(nullptr); //calls func (char*) func(0); //calls func(int)}

nullptr can be used in a sizeof expression. Additionally, you can use nullptr as the argument of a typeid expression:

cout<< typeid(nullptr).name(); //OKsize_t n= sizeof(nullptr); //n=sizeof(void *). 

Throwing and copying nullptr_t objects is also allowed. In the following code listing, the throw statement inside the try block throws nullptr. The matching catch block catches this object by value:

try{ throw nullptr; //OK}catch(std::nullptr_t np) {}

Notice that you cannot take the address of nullptr, though it is possible to take the address of another object of type std::nullptr_t:

template  void func(T) {/**/}func (&nullptr); //error, can't take nullptr's addressstd::nullptr_t nullp;func(&nullp);//OK

Future Directions
The latest draft of the nullptr proposal is available here. Although C++ compilers don't support this feature yet, you can use macros to ensure smooth migration to nulltpr in the near future:

#ifndef __CPP09NULLPTRSUPPORTED  #define NULLPTR (0)#else   #define NULLPTR (nullptr)#endif

C++09 will retain compatibility with older versions of C++. Therefore, 0 will remain in use as a null pointer constant in C++09, in addition to the normative nullptr:

char *pc=0; //OK, pc is a null pointer even in C++09if(ch1==nullptr) //OK

Similarly, the current definition of the macro NULL will not change in C++09.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Related Posts