Question

C++ nullptr Explained: Why It Is Better Than NULL and 0

cpppointersc++11nullptr

Question

In C++11, a new feature called nullptr was introduced, and I want to understand what it is and why it is preferred over NULL.

For example:

int* x = nullptr;
MyClass* obj = nullptr;

I understand that nullptr replaces the older NULL macro, but I do not fully understand how it works.

I have read that nullptr is a keyword and that it has the type std::nullptr_t, which can be implicitly converted to any pointer type or pointer-to-member type. It cannot be implicitly converted to integer types, except bool.

How can something be both a keyword and an instance of a type?

Also, besides the common examples, can you show practical cases where nullptr is better than using 0 or NULL in C++?

Short Answer

By the end of this page, you will understand what nullptr is in C++, why it was added in C++11, how std::nullptr_t relates to it, and why it is safer than NULL or 0. You will also see examples involving overload resolution, comparisons, and real-world coding patterns where nullptr avoids bugs and makes code clearer.

Concept

nullptr is the C++11 null pointer literal. It represents “this pointer points to nothing” in a type-safe way.

Before C++11, programmers often used:

0

or:

NULL

for null pointers. The problem is that 0 is fundamentally an integer literal, and NULL is usually just a macro that expands to 0 or 0L. That means they can behave like integers in contexts where you really intended a pointer.

nullptr fixes this problem.

What nullptr really is

  • nullptr is a keyword in the language.
  • It is a special literal value, similar in spirit to true, false, or numeric literals.
  • The type of that literal is std::nullptr_t.

So these two statements are both true:

  • nullptr is a language keyword.
  • The expression nullptr has the type std::nullptr_t.

That is not unusual in C++. For example:

  • true is a keyword.
  • The expression true has type bool.

Likewise:

  • nullptr is a keyword.
  • The expression nullptr has type std::nullptr_t.

Why this matters

Because std::nullptr_t is a dedicated type for null pointer values:

  • it converts to any raw pointer type,
  • it converts to any pointer-to-member type,
  • it does not act like a normal integer.

This makes code safer and helps the compiler choose the correct function overloads.

Why NULL is weaker

NULL is not magical in C++. It is usually defined like one of these:

#define NULL 0

or:

#define NULL 0L

So when you write:

foo(NULL);

you may actually be passing an integer constant, not a true null pointer literal with its own type.

That can lead to:

  • ambiguous overloads,
  • wrong function calls,
  • less readable code,
  • bugs that nullptr avoids.

Key rule

Use nullptr whenever you mean a null pointer in modern C++.

Mental Model

Think of pointers as street addresses.

  • A normal pointer holds the address of a real house.
  • A null pointer means “no house exists here.”

Before nullptr, C++ often used the number 0 as a special code meaning “no address.” That worked, but it was awkward because 0 is also just the number zero.

So imagine writing on a form:

  • 0 could mean “house number zero” or “no address.”
  • nullptr is like having a dedicated checkbox labeled No Address.

That makes your intent obvious to both the compiler and other programmers.

Another useful analogy:

  • 0 is a general-purpose symbol.
  • nullptr is a purpose-built tool.

If you need to tighten a screw, you can sometimes force a coin to work, but a screwdriver is the right tool. nullptr is the right tool for null pointers.

Take Quiz

Syntax and Examples

Basic syntax

int* p = nullptr;
char* text = nullptr;

This means both pointers currently point to nothing.

Checking for null

if (p == nullptr) {
    std::cout << "p is null\n";
}

You will also often see:

if (!p) {
    std::cout << "p is null\n";
}

That works because pointers can be used in boolean contexts.

Function call example

#include <iostream>

void print(int value) {
    std::cout << "int overload: " << value << "\n";
}

void print(int* ptr) {
    std::cout << "pointer overload\n";
}

int main() {
    print(0);         // calls print(int)
    print(nullptr);   // calls print(int*)
}

Why this is important

If you used NULL and it expands to 0, then:

print(NULL);

might call print(int) instead of the pointer version. That is exactly the kind of bug nullptr prevents.

Another example with templates

#include <iostream>
#include <cstddef>

void check(int*) {
    std::cout << "int pointer\n";
}

void check(std::nullptr_t) {
    std::cout << "nullptr itself\n";
}

int main() {
    check(nullptr);
}

Here, nullptr has its own real type: std::nullptr_t. That is why you can overload on it directly.

Pointer-to-member example

struct MyClass {
    int value;
};

int MyClass::* memberPtr = nullptr;

nullptr also works for pointer-to-member types, not just normal pointers.

Step by Step Execution

Consider this program:

#include <iostream>

void show(int) {
    std::cout << "int version\n";
}

void show(const char*) {
    std::cout << "pointer version\n";
}

int main() {
    show(0);
    show(nullptr);
}

Step-by-step

1. The compiler sees two overloads

void show(int)
void show(const char*)

One accepts an integer, and one accepts a pointer.

2. show(0) is called

show(0);
  • 0 is an integer literal.
  • The best match is show(int).

So the output is:

int version

3. show(nullptr) is called

show(nullptr);
  • nullptr has type std::nullptr_t.
  • It converts naturally to pointer types.
  • The best match is show(const char*).

So the output is:

pointer version

Final output

int version
pointer version

What this demonstrates

Although 0 can be used as a null pointer constant in older C++, it is still an integer literal. nullptr is specifically designed to mean a null pointer, so overload resolution becomes clearer and safer.

Real World Use Cases

1. Initializing pointers safely

FILE* file = nullptr;

This makes it obvious that the pointer does not currently refer to a valid object.

2. Optional ownership or resources

class Logger {
    std::ofstream* stream = nullptr;
};

A null pointer can mean “resource not available yet.”

3. Returning “not found” from pointer-based APIs

Node* findNode(const std::string& id) {
    return nullptr;
}

This clearly signals that no object was found.

4. Linked lists and trees

struct Node {
    int value;
    Node* next = nullptr;
};

Many data structures use null pointers to mark the end or absence of children.

5. Interfacing with older APIs

When working with libraries that still use raw pointers, nullptr expresses null safely:

sendBuffer(nullptr, 0);

6. Callback or handler pointers

void (*handler)(int) = nullptr;

This means no callback is registered yet.

Take Quiz

Real Codebase Usage

In real codebases, nullptr is most commonly used as part of defensive programming and clear intent.

Guard clauses

void process(User* user) {
    if (user == nullptr) {
        return;
    }

    // safe to use user
}

This quickly exits when an invalid pointer is passed.

Constructor member initialization

class Engine {
public:
    Engine() : currentTask(nullptr) {}

private:
    Task* currentTask;
};

This prevents uninitialized pointer bugs.

Error handling in legacy pointer APIs

Connection* connect() {
    if (!serverAvailable()) {
        return nullptr;
    }

    return new Connection();
}

Configuration or optional dependency injection

class Service {
public:
    Service(Logger* logger = nullptr) : logger(logger) {}

private:
    Logger* logger;
};

This means the logger is optional.

Overload clarity

Developers use nullptr to ensure the pointer overload is selected.

openResource(nullptr);

That is much clearer than:

openResource(0);

Modern style note

In modern C++, smart pointers are often preferred over raw pointers for ownership. But even then, nullptr is still used:

std::unique_ptr<Item> item = nullptr;

or:

if (item == nullptr) {
    // no object owned
}

Common Mistakes

1. Using NULL in modern C++

Problem

void log(int);
void log(char*);

log(NULL);

If NULL is 0, the integer overload may be chosen.

Better

log(nullptr);

2. Assuming nullptr is the same as integer zero

Problem

int x = nullptr; // error

nullptr is not an integer.

Fix

Use it only where a pointer-like null value is intended.

int* p = nullptr;

3. Forgetting that null pointers must not be dereferenced

Problem

int* p = nullptr;
std::cout << *p; // undefined behavior

Fix

Check before dereferencing.

if (p != nullptr) {
    std::cout << *p;
}

4. Mixing null checks with unrelated integer logic

Problem

if (p == 0) {
    // works, but less clear
}

Better

if (p == nullptr) {
    // clearly a pointer check
}

5. Thinking nullptr removes all pointer problems

nullptr only improves null pointer representation. It does not solve:

  • dangling pointers,
  • memory leaks,
  • double deletes,
  • ownership confusion.

For those, modern C++ often uses smart pointers and references.

Comparisons

ConceptTypeIntended meaningSafer for overloads?Recommended in modern C++?
0int literalNumeric zero, sometimes null pointer constantNoNo
NULLUsually macro to 0 or 0LNull pointer by conventionNoNo
nullptrstd::nullptr_tNull pointer literalYesYes

nullptr vs 0

  • 0 is an integer literal.
  • nullptr is specifically a null pointer literal.
  • nullptr avoids accidental calls to integer overloads.

nullptr vs NULL

  • NULL is usually a macro, not a real language feature.
  • nullptr is a keyword with its own type.
  • nullptr is clearer, safer, and more modern.

nullptr vs uninitialized pointer

int* p;          // uninitialized, dangerous
int* q = nullptr; // initialized safely

An uninitialized pointer contains garbage. nullptr is a known safe state meaning “points to nothing.”

Take Quiz

Cheat Sheet

Quick reference

Declare a null pointer

int* p = nullptr;

Check for null

if (p == nullptr) {}
if (p != nullptr) {}
if (!p) {}

Important facts

  • nullptr was added in C++11.
  • nullptr is a keyword.
  • The type of nullptr is std::nullptr_t.
  • It converts to any pointer type.
  • It converts to any pointer-to-member type.
  • It does not convert to normal integer types.
  • Prefer nullptr over NULL and 0.

Good uses

MyClass* obj = nullptr;
return nullptr;
functionTakingPointer(nullptr);

Avoid

MyClass* obj = 0;
MyClass* obj = NULL;

Common edge case

Overloads:

void f(int);
void f(char*);

Then:

f(0);        // int overload
f(nullptr);  // pointer overload

FAQ

What is the type of nullptr in C++?

The type of nullptr is std::nullptr_t.

Is nullptr a keyword or an object?

It is a keyword that denotes a special literal value. That literal has the type std::nullptr_t.

Why is nullptr better than NULL?

nullptr has its own type and behaves like a real null pointer literal. NULL is usually just a macro for 0, which can cause overload and type-safety problems.

Why is nullptr better than 0?

0 is an integer literal. nullptr is specifically for pointers, so it is clearer and safer.

Can nullptr be compared with pointers?

Yes. It can be compared with any pointer type and pointer-to-member type.

Can nullptr be assigned to an int?

No. It is not implicitly convertible to normal integer types.

Does nullptr work with smart pointers?

Yes. Smart pointers like std::unique_ptr and std::shared_ptr can be initialized or compared with nullptr.

Should I still use NULL in modern C++?

No. In modern C++, prefer nullptr whenever you mean a null pointer.

Take Quiz

Mini Project

Description

Build a small C++ program that simulates looking up a user by ID and returning a pointer. This project demonstrates how nullptr is used to represent “not found,” how to check for null safely, and how it improves readability over 0 or NULL. It also reinforces safe pointer initialization and basic function design.

Goal

Create a program that searches for a user and prints either the user name or a clear “not found” message using nullptr safely.

Requirements

[ "Define a User struct with an id and a name.", "Create a function that returns a User pointer and returns nullptr when no match is found.", "Store a small fixed collection of users and search through it.", "Check the returned pointer before dereferencing it.", "Print a success message when a user is found and a failure message when the result is nullptr." ]

Take Quiz

Keep learning

Related questions

View more