C++ 2011: nullptr

C++ used to lack a special value to indicate a null pointer. It used 0 for this purpose, something that was inherited from C. This led to some problems, which we'll show in this article. The new standard introduces a new reserved word nullptr, to designate a constant rvalue that represents a null pointer.

NULL is ZERO

In C++ a null pointer is:

A null pointer constant is an integral constant expression (expr.const) rvalue of integer type that evaluates to zero.

This was inherited from C where

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

Since there is no keyword in the language for a null pointer, both C and C++ compiler provide an implementation-dependent macro called NULL. In VC++ and GCC this is defined as:

#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif

Integer 0 implicitly converts to any pointer type. The use of 0 as a special value for null pointers can lead to some issues, the most important being with calling overloaded functions. Let's look at these two overloaded functions:

void foo(int)   {cout << "int" << endl;}
void foo(char*) {cout << "pointer" << endl;}

The q uestion is, which of the two would be called for foo(0)? The answer is the first one. To be able to call the second one with a null pointer an explicit cast to char* should be made, i.e. foo((char*)0). On the other hand, the following line of code is valid and calls that constructor of std::basic_string that takes a char*:

string str(false);

The nullptr Reserved Word

The new standard introduces a reserved word called nullptr to represent a null pointer. It designates a constant rvalue of type decltype(nullptr):

typedef decltype(nullptr) nullptr_t;

The nullptr_t type:

  • Is a typedef for decltype(nullptr)
  • Is a POD type convertible to a pointer type and pointer-to-member type
  • Objects of this type can be copied and thrown
  • It is possible to take the address of a nullptr_t object
  • reinterpret_cast to/from a nullptr_t object is possible
  • nullptr_t matches a T* and a T::* partial specialization

The nullptr:

  • Is a literal (just like 0 or false)
  • The address of nullptr cannot be taken
  • Can be used with sizeof, typeid and ternary conditional operator

It is important to note that the standard library macro NULL is not (re-)defined to nullptr; the result of that would be a lot of broken code.

It is possible to use 0 (NULL) and nullptr interchangeably (which is important for compatibility), like in the following examples:

int* p1 = 0;
int* p2 = nullptr;

if(p1 == 0) {}
if(p2 == 0) {}
if(p1 == nullptr) {}
if(p2 == nullptr) {}
if(p1 == p2) {}
if(p2) {}

It is not possible however to assign nullptr to an integer value, nor to compare nullptr to an integer.

int n1 = 0;             // ok
int n2 = nullptr;       // error

if(n1 == nullptr) {}    // error
if(n2 == nullptr) {}    // error
if(nullprt) {}          // error

Also, because nullptr is an rvalue constant, it's not possible to assign it a value.

nullptr = 0;

For the overloading problem presented in the previous paragraph, use of nullptr would call the overload that takes a char*.

void foo(int)   {cout << "int" << endl;}
void foo(char*) {cout << "pointer" << endl;}

foo(0);       // calls foo(int)
foo(nullptr); // calls foo(char*)

nullptr can be used with the ternary conditional operator:

int* p1 = ...;
int* p2 = true ? p1 : nullptr;

However, the following cases are erroneous:

int* p2 = true ? 0 : nullptr;       // incompatible types
int n1 = true ? nullptr : nullptr;  // nullptr cannot be converted to int
int n2 = true ? 0 : nullptr;        // incompatible types

Given these two template functions:

template<typename T>
void fooptr(T* t);

template<typename T>
void foo(T t);

The following cases are possible:

fooptr((int*)0);        // type T deduced to int
fooptr((int*)nullptr);  // type T deduced to int

foo(0);                 // type T deduced to int
foo((int*)0);           // type T deduced to int*
foo(nullptr);           // type T deduced to nullptr_t
foo((int*)nullptr);     // type T deduced to int*

while these are errors:

fooptr(0);              // error, type T cannot be deduced
fooptr(nullptr);        // error, type T cannot be deduced

Conclusions

The new C++ standard defines a reserved word nullptr (representing a constant rvalue of type nullptr_t) that designates a null pointer. For compatibility reasons 0 can still be used as null pointer, and 0 and nullptr can be used interchangeably; also for compatibility reasons, macro NULL will not be redefined to nullptr.



About the Author

Marius Bancila

Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. He is the co-founder of codexpert.ro, a community for Romanian C++/VC++ programmers.

Related Articles

Comments

  • thanks

    Posted by liveevil on 12/29/2011 09:22pm

    thanks for sharing the latest information about the newly C++2011 standardo Reply

  • C++ 2011: nullptr

    Posted by Cql_liliang on 11/18/2011 10:44pm

    hi ,  Marius Bancila , maybe you have an error. 
    
    if(nullprt) {}          // error
    
    is not if(nullptr){}  ?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

  • Instead of only managing projects organizations do need to manage value! "Doing the right things" and "doing things right" are the essential ingredients for successful software and systems delivery. Unfortunately, with distributed delivery spanning multiple disciplines, geographies and time zones, many organizations struggle with teams working in silos, broken lines of communication, lack of collaboration, inadequate traceability, and poor project visibility. This often results in organizations "doing the …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds