Что произойдет, если разыменовать нулевой (nullptr) указатель в C++?

«Что произойдет, если разыменовать нулевой (nullptr) указатель в C++?» — вопрос из категории C++ Core, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Разыменование нулевого указателя (например, *ptr, где ptr == nullptr) или вызов метода через такой указатель (ptr->method()) приводит к неопределенному поведению (Undefined Behavior, UB) согласно стандарту C++.

Что это значит на практике? Компилятор и исполняющая среда не гарантируют никакого конкретного результата. Возможные последствия включают, но не ограничиваются:

  1. Немедленный крах программы: Наиболее частый сценарий. Операционная система обнаруживает попытку доступа к защищенной памяти по адресу 0 и отправляет сигнал (например, SIGSEGV на Linux), вызывая аварийное завершение.
  2. Тихий крах или порча данных: Программа может продолжить работу с некорректными данными, что позже приведет к непредсказуемым и трудноотлаживаемым ошибкам.
  3. Неожиданная оптимизация: Поскольку стандарт говорит, что UB «не должно происходить», компилятор может делать агрессивные предположения. Например, он может удалить целые ветки кода, которые, по его логике, ведут к UB.

Пример опасного кода и защита:

#include <iostream>

void unsafe(int* p) {
    std::cout << *p << std::endl; // UB, если p == nullptr
}

void safe(int* p) {
    // Всегда проверяйте указатель перед разыменованием
    if (p != nullptr) { // или просто if(p)
        std::cout << *p << std::endl;
    } else {
        std::cout << "Ошибка: передан нулевой указатель" << std::endl;
    }
}

void safeWithReferences(int* p) {
    // Использование ссылок на этапе проектирования API помогает избежать проблемы.
    // Функция, принимающая ссылку, требует валидный объект.
}

int main() {
    int* nullPtr = nullptr;
    // unsafe(nullPtr); // Потенциальный крах (SIGSEGV)
    safe(nullPtr);      // Безопасная обработка
    return 0;
}

Вывод: Разыменование nullptr — одна из самых распространенных и опасных ошибок в C++. Всегда инициализируйте указатели, проверяйте их на nullptr перед использованием и отдавайте предпочтение ссылкам и умным указателям (std::unique_ptr, std::shared_ptr), которые обеспечивают более строгую семантику владения.