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