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: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today makes data protection a must-have, as we live in a data-driven society -- the digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join Seagate Cloud …

  • Event Date: April 15, 2014 The ability to effectively set sales goals, assign quotas and territories, bring new people on board and quickly make adjustments to the sales force is often crucial to success--and to the field experience! But for sales operations leaders, managing the administrative processes, systems, data and various departments to get it all right can often be difficult, inefficient and manually intensive. Register for this webinar and learn how you can: Align sales goals, quotas and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds