C++ nullptr vs NULL | Type-Safe Null Pointers

C++ nullptr vs NULL | Type-Safe Null Pointers

이 글의 핵심

`nullptr` is a pointer literal of type `std::nullptr_t`. `NULL` and `0` are integral—use `nullptr` for clarity and correct overload and template behavior.

Introduction

nullptr (C++11) is a type-safe null pointer literal. Unlike NULL or 0, it has type std::nullptr_t and participates correctly in overload resolution and template deduction.


1. Basics

#include <iostream>

int main() {
    int* ptr1 = NULL;    // implementation-defined (often 0)
    int* ptr2 = 0;       // integer literal
    int* ptr3 = nullptr; // std::nullptr_t -> pointer

    std::cout << ptr1 << "\n";
    std::cout << ptr2 << "\n";
    std::cout << ptr3 << "\n";
    return 0;
}

std::nullptr_t overloads

#include <cstddef>

void func(std::nullptr_t) {
    std::cout << "nullptr_t\n";
}

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

int main() {
    func(nullptr);  // nullptr_t
    // func(NULL);  // ambiguous or wrong: usually calls int
    func(0);        // int
    return 0;
}

2. Problems with NULL

Overload resolution

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

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

int main() {
    process(0);        // int
    process(NULL);   // often int—not pointer!
    process(nullptr); // pointer overload
    return 0;
}

NULL is typically 0 or 0L—an integer, not a pointer type.

Template deduction

template<typename T>
void func(T value) {
    std::cout << typeid(T).name() << "\n";
}

int main() {
    func(0);        // T = int
    func(NULL);     // T = int or long
    func(nullptr);  // T = std::nullptr_t
    return 0;
}

auto deduction

auto p1 = NULL;     // integral
auto p2 = nullptr;  // std::nullptr_t

int* q = p2;  // OK

3. Using nullptr

Initialization

int* p1 = nullptr;
std::unique_ptr<int> u = nullptr;
std::shared_ptr<int> s = nullptr;
void (*fp)() = nullptr;

Checks

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

Return values

int* find(int) {
    return nullptr;  // clear “no result”
}

4. Examples

Linked list

struct Node {
    int data;
    Node* next;
    Node(int d) : data(d), next(nullptr) {}
};

Repository returning “not found”

User* findById(int id) {
    if (id == 1) return &someUser;
    return nullptr;
}

5. Comparison table

nullptrNULL0
Typestd::nullptr_tintegralint
Overloadspointerintint
Template Tnullptr_tintint
RecommendedYesLegacyLegacy

6. Migration

Before

int* ptr = NULL;
if (ptr == NULL) { }
void f(Widget* w = NULL);

After

int* ptr = nullptr;
if (ptr == nullptr) { }
void f(Widget* w = nullptr);

clang-tidy

clang-tidy -checks='-*,modernize-use-nullptr' -fix program.cpp

Summary

  1. nullptr: C++11 pointer literal
  2. NULL: legacy macro, integral
  3. Overloads: nullptr selects pointer overloads
  4. Templates: clear deduction
  5. Performance: no runtime difference

Principles: Prefer nullptr in C++11+; compare with == nullptr or !ptr.

Related: C++ nullptr, Smart pointers.


  • C++ nullptr
  • C++ async & launch

Keywords

C++, nullptr, NULL, null pointer, C++11, std::nullptr_t.


  • C++ Atomic operations
  • C++ auto keyword