Null pointers
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)
andf(char*)
, the callf(0)
resolves tof(int)
because0
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.
- It is impossible to distinguish between a null pointer and integer
0 for overloaded functions. For example, given two overloaded functions
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;
}
}