nullptr
The null pointer literal introduced in C++11, typed as std::nullptr_t, that replaces NULL and 0 in pointer contexts with full type safety.
nullptrsince C++11nullptr is a keyword and prvalue of type std::nullptr_t that represents the universally null pointer constant, converting implicitly to any pointer or pointer-to-member type but never to an integer type.
Overview
Before C++11, null pointers were expressed as the integer literal 0 or the macro NULL, which typically expands to 0 or (void*)0 depending on the implementation. Both are fundamentally integer values that the compiler permits in pointer contexts through implicit conversion. This creates two distinct problems: overload resolution becomes ambiguous between pointer and integer overloads, and generic code loses the null-pointer meaning when the integer constant is deduced as int.
C++11 introduced nullptr as a dedicated null pointer literal with its own type: std::nullptr_t, declared in <cstddef>. This type is distinct from all pointer types, yet it converts implicitly to any pointer type and any pointer-to-member type. Critically, it does not convert to int or any other arithmetic type. That single distinction eliminates the class of overload ambiguity and template deduction failures that plagued pre-C++11 null pointer handling.
nullptr is a keyword, not a macro. It is a prvalue (pure rvalue) in the sense of C++11 value categories β it has no identity, no address, and cannot appear on the left-hand side of an assignment. Every expression of type std::nullptr_t is a null pointer constant, meaning it converts to null of any pointer type.
std::nullptr_t is a complete, regular type. Variables may be declared of type std::nullptr_t, it may appear as a template argument, it participates in overload resolution as its own distinct type, and since C++11 it may appear in constant expressions evaluated at compile time.
Syntax
nullptrThe keyword itself requires no header. To name the type std::nullptr_t explicitly in code, include <cstddef>.
#include <cstddef>
std::nullptr_t np = nullptr; // C++11: variable of type std::nullptr_t
int* ip = nullptr; // C++11: null int*
void (*fn)() = nullptr; // C++11: null function pointer
int Foo::* mp = nullptr; // C++11: null pointer-to-data-memberExamples
Overload Resolution β The Core Motivation
#include <cstddef>
#include <iostream>
void process(int n) { std::cout << "integer: " << n << '\n'; }
void process(int* p) { std::cout << "pointer: " << (p ? "non-null" : "null") << '\n'; }
int main()
{
process(0); // calls process(int) β may surprise callers
process(NULL); // calls process(int) β NULL is an integer constant
process(nullptr); // calls process(int*) β unambiguous, C++11
}With 0 or NULL, the compiler resolves to process(int) because those are integer constants. nullptr has type std::nullptr_t, which does not convert to int, leaving only the pointer overload viable.
Templates and Type Deduction
nullptr retains its identity through template instantiation; 0 and NULL do not:
#include <cstddef>
#include <iostream>
template<class T>
constexpr T forwarded(const T& v) { return v; } // C++11
void sink(int*) { std::cout << "pointer\n"; }
int main()
{
sink(forwarded(nullptr)); // OK: T = std::nullptr_t, converts to int*
// sink(forwarded(0)); // error: T = int, not convertible to int*
// sink(forwarded(NULL)); // error: same β NULL deduces as int
}This distinction is critical in middleware and generic wrappers that forward null sentinels through multiple levels of deduction. nullptr is the only null constant that survives deduction intact.
Overloading on std::nullptr_t
When a type should accept only nullptr and reject arbitrary integers, overload its constructor or assignment operator on std::nullptr_t directly:
#include <cstddef>
class Handle {
public:
explicit Handle(void* raw) noexcept : ptr_(raw) {}
Handle(std::nullptr_t) noexcept : ptr_(nullptr) {} // C++11: reset overload
Handle& operator=(std::nullptr_t) noexcept { // C++11
ptr_ = nullptr;
return *this;
}
explicit operator bool() const noexcept { return ptr_ != nullptr; }
private:
void* ptr_;
};
Handle h{nullptr}; // uses Handle(std::nullptr_t)
h = nullptr; // uses operator=(std::nullptr_t)
// Handle bad{0}; // error: no conversion from int to HandleThis pattern is used throughout the standard library in std::unique_ptr, std::shared_ptr, and std::function to provide clean reset semantics without accidentally accepting 0.
auto and nullptr
auto deduces std::nullptr_t, not a pointer type:
auto p = nullptr; // p is std::nullptr_t β NOT void*, NOT int*
// *p; // error: cannot dereference std::nullptr_t
int* ip = nullptr; // explicit type: fine
auto q = static_cast<int*>(nullptr); // C++11: force pointer type via castWhen you need a typed null pointer via auto, either declare the type explicitly or cast. This deduction behaviour can surface as an error far from the declaration site, so explicit pointer types are preferable in these situations.
Equality and Comparison
nullptr compares equal to any null pointer value of any pointer type:
#include <cstddef>
int* p = nullptr;
void* q = nullptr;
bool a = (p == nullptr); // true
bool b = (q == nullptr); // true
// bool c = (p == q); // error: cannot compare int* and void* directly
std::nullptr_t n1 = nullptr;
std::nullptr_t n2 = nullptr;
bool d = (n1 == n2); // true: all std::nullptr_t values compare equal
bool e = (n1 < n2); // false: relational operators are also defined (C++11)Best Practices
Always use nullptr instead of NULL or 0 in pointer contexts. The type distinction is enforced by the compiler and prevents silent resolution to integer overloads.
Overload on std::nullptr_t when a class has a distinct "reset to null" operation. This makes the API explicit, prevents accidental construction from the integer 0, and documents intent at the call site.
Do not use auto to capture nullptr when you need a pointer. Declare the concrete pointer type or assign to a typed pointer first. The std::nullptr_t type has no dereference, arithmetic, or indexing operations.
In generic code, always pass nullptr rather than 0 through deduction contexts. A 0 that enters template<class T>(T v) becomes int and loses all pointer-convertibility. nullptr never does.
Prefer std::nullptr_t parameters over pointer parameters for factory/reset functions when the semantic meaning is strictly "set to null," not "accept any pointer." It prevents callers from accidentally passing live pointers.
Common Pitfalls
sizeof(std::nullptr_t) Is Not Guaranteed to Match sizeof(void*)
std::nullptr_t is an independent type. Its size is implementation-defined and need not match any pointer size:
// May or may not hold on a given platform:
static_assert(sizeof(std::nullptr_t) == sizeof(void*)); // NOT guaranteedDo not use std::nullptr_t as a proxy for pointer size in low-level code.
Boolean Conversion Is Always false
A value of type std::nullptr_t is always null by definition. Boolean conversion always yields false, and compilers typically warn on if (nullptr):
std::nullptr_t n = nullptr;
if (n) { /* unreachable */ } // compiler warning; condition is always falseThe warning is correct. There is no way to construct a non-null std::nullptr_t.
Null Pointer-to-Member Is Legal but Dangerous
nullptr converts to pointer-to-member types, which is syntactically valid but undefined behaviour if dereferenced:
struct Foo { int x; };
int Foo::* mp = nullptr; // legal: null pointer-to-data-member
Foo obj;
// obj.*mp; // undefined behaviour: dereferencing null pointer-to-memberThe type system does not prevent this. The hazard is identical to dereferencing a null object pointer but occurs in a context developers may not expect to be dangerous.
nullptr Cannot Be Passed to a Variadic Function Correctly
Because variadic functions (printf, va_list-based APIs) do not have typed parameters, nullptr is passed as std::nullptr_t, not as void*. On platforms where the two have different representations or sizes this causes undefined behaviour:
printf("%p\n", nullptr); // undefined behaviour
printf("%p\n", (void*)nullptr); // correct: explicit cast to void*Always cast nullptr to the expected pointer type before passing it to C-style variadic interfaces.
See Also
std::nullptr_tβ the type ofnullptr, declared in<cstddef>(C++11); usable as a template parameter and function parameter typeNULLβ the legacy null pointer macro from<cstddef>and related headers; prefernullptrin all new C++11 and later codeautoβ type deduction;auto x = nullptrdeducesstd::nullptr_t, not any pointer type