C++ 2011: nullptr

来源:互联网 发布:string数组中删除元素 编辑:程序博客网 时间:2024/04/29 12:51

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;             // okint n2 = nullptr;       // errorif(n1 == nullptr) {}    // errorif(n2 == nullptr) {}    // errorif(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 typesint n1 = true ? nullptr : nullptr;  // nullptr cannot be converted to intint 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 intfooptr((int*)nullptr);  // type T deduced to intfoo(0);                 // type T deduced to intfoo((int*)0);           // type T deduced to int*foo(nullptr);           // type T deduced to nullptr_tfoo((int*)nullptr);     // type T deduced to int*

while these are errors:

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

Conclusions

The new C++ standard defines a reserved word nullptr (representing a constant rvalue of typenullptr_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.

Keywords: C++ 0XC++NULLPTR

About the Author

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.



原创粉丝点击