Открыть сервис

Nullptr

nullptr — это ключевое слово (литерал) в языках программирования C++ (начиная со стандарта C++11) и C (начиная с C23), обозначающее нулевой указатель. Оно представляет собой константу, которая может быть неявно преобразована в любой тип указателя или указателя на член класса, но не может быть преобразована в целочисленный тип (кроме типа bool). Введение nullptr было призвано устранить неоднозначности и ошибки, связанные с использованием макроса NULL или целочисленного нуля (0) в контексте указателей.

История

До стандарта C++11 в языке C++ для обозначения нулевого указателя традиционно использовались макрос NULL (обычно определённый как 0 или (void*)0) или непосредственно целочисленный ноль. Это приводило к проблемам, особенно при перегрузке функций. Например, вызов f(0) мог быть интерпретирован как вызов функции с целочисленным параметром, а не с параметром-указателем, что было источником трудноуловимых ошибок.

В 2005 году программист Херб Саттер (Herb Sutter) и Бьярн Страуструп (Bjarne Stroustrup) предложили ввести в C++ новый литерал для нулевого указателя, который был бы типобезопасным и не допускал неявного преобразования в целые числа. Предложение было принято, и в стандарте C++11 появился nullptr.

В языке C аналогичная проблема решалась дольше. Хотя стандарт C99 допускал использование (void*)0 для нулевого указателя, это не было отдельным ключевым словом. В стандарте C23 было решено ввести nullptr как ключевое слово, аналогичное C++.

Синтаксис и семантика

nullptr является ключевым словом и литералом. Его тип — std::nullptr_t (в C++) или nullptr_t (в C23), определённый в заголовочном файле <cstddef> (C++) или <stddef.h> (C). Этот тип не является указателем, но может быть неявно преобразован в любой тип указателя или указателя на член класса.

Основные свойства:

  • nullptr не может быть преобразован в целочисленный тип, за исключением bool (где он преобразуется в false).
  • nullptr можно сравнивать с другими указателями и с nullptr.
  • nullptr не может быть разыменован (попытка разыменования приводит к неопределённому поведению).
  • nullptr является константой времени компиляции.

Пример объявления и инициализации: ``cpp int ptr = nullptr; // корректно void vptr = nullptr; // корректно int n = nullptr; // ошибка компиляции: неявное преобразование запрещено bool b = nullptr; // корректно: b == false ``

Преимущества перед NULL и 0

  1. Типобезопасность: nullptr имеет собственный тип, что исключает неоднозначность при перегрузке функций. Например, если есть две перегруженные функции void f(int) и void f(char*), то вызов f(nullptr) вызовет вторую версию, тогда как f(0) или f(NULL) вызовет первую.
  1. Явность намерения: Использование nullptr чётко указывает, что речь идёт о нулевом указателе, а не о целочисленном нуле.
  1. Совместимость с шаблонами: В шаблонном коде nullptr ведёт себя предсказуемо, в то время как NULL может вести себя по-разному в зависимости от реализации.
  1. Улучшенная диагностика: Компиляторы могут выдавать более точные предупреждения об ошибках, связанных с использованием nullptr, по сравнению с NULL.

Использование в C++

В C++ nullptr является стандартным способом обозначения нулевого указателя. Он используется повсеместно:

  • Инициализация указателей: int* p = nullptr;
  • Проверка на нулевой указатель: if (ptr == nullptr) { ... }
  • Возврат из функций: return nullptr;
  • В шаблонных функциях и классах: std::unique_ptr<int> up(nullptr);

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

Использование в C (C23)

В стандарте C23 nullptr введён как ключевое слово, аналогичное C++. Он определён в заголовочном файле <stddef.h> и имеет тип nullptr_t. Использование аналогично C++:

``c int* p = nullptr; if (p == nullptr) { ... } ``

До C23 в C для нулевого указателя использовался макрос NULL (обычно (void*)0), который не обеспечивал типобезопасности. Введение nullptr в C23 решило эту проблему, сделав код на C более безопасным.

Тип std::nullptr_t

std::nullptr_t (или nullptr_t в C) — это тип, который может принимать только одно значение: nullptr. Он определён в заголовочном файле <cstddef> (C++) или <stddef.h> (C). Этот тип может быть использован для перегрузки функций, когда требуется различать вызовы с нулевым указателем и с целочисленным нулём.

Пример: ```cpp void f(int) { std::cout << "int"; } void f(std::nullptr_t) { std::cout << "nullptr"; }

f(0); // выводит "int" f(nullptr); // выводит "nullptr" ```

Особенности и нюансы

  • nullptr не является указателем, а лишь литералом, который может быть преобразован в указатель. Это означает, что sizeof(nullptr) равен sizeof(std::nullptr_t), который обычно равен размеру указателя (4 или 8 байт), но не обязательно.
  • В C++ nullptr может быть неявно преобразован в bool (как false), но не в целые числа. Это позволяет использовать nullptr в условных выражениях.
  • В C++ nullptr не может быть преобразован в void неявно, если void не является целевым типом. Однако nullptr может быть присвоен void* напрямую.
  • Некоторые компиляторы (например, GCC, Clang, MSVC) поддерживают nullptr начиная с C++11, а в C — с C23.

Критика и альтернативы

Введение nullptr было воспринято положительно, но некоторые разработчики отмечали, что:

  • nullptr не решает проблему «нулевого указателя» как концептуальной ошибки дизайна (например, отсутствие обязательной проверки на nullptr).
  • В некоторых старых кодовых базах переход на nullptr требует значительных изменений.
  • В C++ существует альтернативный подход — использование std::optional или std::variant для явного указания на отсутствие значения, что может быть предпочтительнее в некоторых случаях.

Тем не менее, nullptr стал стандартом де-факто в C++ и постепенно внедряется в C.

Источники

  • Стандарт ISO/IEC 14882:2011 (C++11), раздел 2.14.7.
  • Стандарт ISO/IEC 9899:2023 (C23), раздел 6.4.4.4.
  • Саттер Х., Страуструп Б. «A Name for the Null Pointer» (2005).
  • Страуструп Б. «Язык программирования C++», 4-е издание.
  • Документация компиляторов GCC, Clang, MSVC.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →