A null pointer has a reserved value that is called a null
pointer constant for indicating that the pointer does not point to
any valid object or function. You can use null pointers in the following
cases:
- Initialize pointers.
- Represent conditions such as the end of a list of unknown length.
- Indicate errors in returning a pointer from a function.
A null pointer constant is an integer constant expression
that evaluates to zero. For example, a null pointer constant can be
0, 0L, or such an expression that can be cast to
type (void *)0. C++11 defines a new null pointer constant nullptr that
can only be converted to any pointer type, pointer-to-member type,
or bool type.
You can specify any of the following
values for a null pointer constant:
- 0
- NULL
- nullptr
Note: NULL is a macro. It must be defined before
use.
Null pointer constants
- 0
- You can use an integer constant expression with the value 0 or
an expression that is cast to(void *)0 as a null
pointer constant.
- NULL
- The macro NULL and value 0 are equivalent as null pointer constants,
but NULL is cleaner because it represents the purpose of using the
constant for a pointer.
- nullptr
- nullptr is an explicit null pointer constant.
In C++, initializing null pointers with 0 or NULL have the following
problems:
- It is impossible to distinguish between a null pointer and integer
0 for overloaded functions. For example, given two overloaded functions f(int) and f(char*),
the call f(0) resolves to f(int) because 0 is
converted to the integral type instead of the pointer type. See Example 1.
- A null pointer constant does not have a type-safe name. The macro
NULL cannot be distinguished from the 0 constant
for overloaded functions and error detection.
- To solve the problems of null pointer constants, C++11 introduced
a new keyword nullptr. The nullptr constant
can be distinguished from integer 0 for overloaded functions. See Example 2.
- A null pointer constant with the nullptr value
has the following characteristics:
- It can be converted to any pointer or pointer-to-member type.
- It cannot be implicitly converted to any other type, except for
the bool type.
- It cannot be used in an arithmetic expression.
- It can be compared with the integer 0.
- It can be used in relational expressions to compare with pointers
or data of the std::nullptr_t type.
See Example 3 for information
about how to use nullptr as an initializer for all
pointer types and in comparison expressions.
Note: It is still
acceptable to assign the value 0 or NULL to a pointer.
The
nullptr keyword designates a constant
rvalue of type
decltype(nullptr). The typedef expression
is
typedef decltype(nullptr) nullptr_t, of which
nullptr_t is
a typedef for
decltype(nullptr) that is defined in
<cstddef>.
A non-type template parameter and argument can have the
std::nullptr_t type.
If a non-type template parameter is of type
std::nullptr_t,
the corresponding argument must be of type
std::nullptr_t.
See
Example 4. If a non-type
template parameter is of one of the following types, the type of the
corresponding non-type template argument can be
std::nullptr_t.
The null pointer conversion occurs for the last three types:
- std::nullptr_t
- pointer
- pointer-to-member
- bool
- When you use nullptr in exception handling, pay
attention to the throw and catch arguments.
A handler is a match for an exception object of type E if
the handler is of type cv T or const T&. T is
a pointer or pointer-to-member type and E is of type std::nullptr_t.
See Example 5.
Examples
Example
1
This example illustrates inappropriate use of the NULL constant
for overloaded functions:
#include <stdio.h>
void func(int* i){
printf("func(int*)\n");
}
void func(int i){
printf("func(int)\n");
}
int main(){
func(NULL);
}
Suppose you want the main function to call
func(int*
i). As a result, the
main function calls
func(int
i) instead of
func(int* i) because the constant
NULL is equal to the integer 0. Constant 0 is implicitly converted
to
(void*)0, only when
func(int i) does
not exist.
Example 2
This example illustrates
how
nullptr is used in overloading functions:
void f( char* );
void f( int );
f( nullptr ); // calls f( char* )
f( 0 ); // calls f( int )
Example
3
The following expressions illustrate the correct and incorrect
use of the
nullptr constant:
char* p = nullptr; // p has the null pointer value
char* p1 = 0; // p has the null pointer value
int a = nullptr; // error
int a2 = 0; // a2 is zero of integral type
if( p == 0 ); // evaluates to true
if( p == nullptr ); // evaluates to true
if( p ); // evaluates to false
if( a2 == 0 ); // evaluates to true
if( a2 == nullptr ); // error, no conversion
if( nullptr ); // OK, conversion to the bool type
if( nullptr == 0 ); // OK, comparison with 0
nullptr = 0; // error, nullptr is not an lvalue
nullptr + 2; // error
Example
4
This example illustrates that a non-type template parameter
or argument can have the
std::nullptr_t type:
typedef decltype(nullptr) nullptr_t;
template <nullptr_t> void fun1(); // non-type template parameter
fun1<nullptr>(); // non-type template arguments
fun1<0>(); // error. The corresponding argument must be of type
// std::nullptr_t if the parameter is of type std::nullptr_t.
template <int* p> void fun2();
fun2<nullptr>(); //Correct
template<typename T> void h( T t );
h( 0 ); // deduces T = int
h( nullptr ); // deduces T = nullptr_t
h( (float*) nullptr ); // deduces T = float*
Example 5
This example illustrates
how to use
nullptr in exception handling:
int main() {
try {
throw nullptr;
} catch(int* p) { // match the pointer.
return p == 0;
}
}