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

  • Software Architect

    Posted by Ashwani Kumar on 07/26/2014 09:02am

    Very useful and clear article.

    Reply
  • 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

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • With the average hard drive now averaging one terabyte in size, the fallout from the explosion of user-created data has become an overwhelming volume of potential evidence that law-enforcement and corporate investigators spend countless hours examining. Join Us and SANS' Rob Lee for our 45-minute webinar, A Triage and Collection Strategy for Time-Sensitive Investigations, will demonstrate how to: Identify the folders and files that often contain key insights Reduce the time spent sifting through content by …

Most Popular Programming Stories

More for Developers

RSS Feeds