Используйте nullptr вместо NULL

Всегда используйте nullptr вместо NULL или 0 для указателей.

nullptr - это ключевое слово, введенное в C++11, для обозначения нулевого значения указателя. Это не число 0, а особая константа специального указательного типа std::nullptr_t.

nullptr типобезопасен, не путает перегрузки и явно выражает намерение "здесь указатель, который ни на что не указывает". NULL остался в наследие от C - в современном C++ ему не место.

Неправильно:

void foo(int x) {
    std::cout << "Вызван foo(int): " << x << '\n';
}

void foo(char* ptr) {
    std::cout << "Вызван foo(char*): " << (ptr ? "не null" : "null") << '\n';
}

int main() {
    foo(NULL);  // Что вызовется?
    foo(0);     // А здесь?
}

Проблема: NULL — это макрос, который раскрывается в 0 (или 0L). Поэтому оба вызова уйдут в foo(int), а не в foo(char*), как мог ожидать программист. Это классический баг, который компилятор не ловит (если только не включены специальные предупреждения). Более того, NULL не несёт информации о том, что это именно указатель.

Правильно:

void foo(int x) {
    std::cout << "Вызван foo(int): " << x << '\n';
}

void foo(char* ptr) {
    std::cout << "Вызван foo(char*): " << (ptr ? "не null" : "null") << '\n';
}

int main() {
    foo(NULL);     // Вызовется foo(int)
    foo(nullptr);  // Однозначно вызывает foo(char*)
}

nullptr имеет собственный тип std::nullptr_t, который неявно приводится к любому указателю, но не приводится к целочисленным типам. Перегрузка разрешается корректно, а случайная передача в int становится ошибкой компиляции.

Другие плюсы nullptr:

auto p = NULL;   // p — int (или long)
auto q = nullptr; // q — std::nullptr_t, безопасно

if (p == nullptr) {} // Ок, но p — не указатель, просто 0
if (q == 0)       {} // Тоже ок, nullptr сравним с 0