Может ли NULL-макрос быть нулевым?
Согласно проекту стандарта N4713 (7.11/1):
Константа нулевого указателя представляет собой целочисленный литерал (5.13.2) со значением 0 или prvalue типа std::nullptr_t
.
и 21.2.3/2:
Макрос NULL
представляет собой константу нулевого указателя, определяемую реализацией.
следует, что NULL
можно определить как nullptr
. То же самое упоминается в cppreference:
#define NULL 0
//since C++11
#define NULL nullptr
В то же время в пункте "Аддитивные операторы" говорится (8.5.6/7):
Если значение 0
добавляется или вычитается из значения нулевого указателя, результатом является значение нулевого указателя. Если два значения нулевого указателя вычитаются, результат сравнивается с значением 0
преобразованным в тип std::ptrdiff_t
.
Следовательно, следующий код должен быть действительным:
0 + nullptr;
nullptr - nullptr;
но из-за отсутствия операторов + / - для std::nullptr_t
код недействителен.
Есть ли что-то, что я не принимал во внимание, или NULL
макрос не может быть фактически определен как nullptr
?
Ответы
Ответ 1
Хотя nullptr
является константой нулевого указателя, это не значение нулевого указателя. Последний является значением некоторого типа указателя, который std::nullptr_t
не является.
Ссылка:
Константа нулевого указателя представляет собой целочисленный литерал (5.13.2) со значением 0 или prvalue типа std::nullptr_t
. Константа нулевого указателя может быть преобразована в тип указателя; результатом является нулевое значение указателя этого типа и отличается от любого другого значения указателя объекта или типа указателя функции. Такое преобразование называется преобразованием нулевого указателя. [...]
7.11/1 в N4659, подчеркнуть мою
Таким образом, NULL
действительно может быть nullptr
без предоставления арифметических операторов.
Ответ 2
nullptr
- литерал нулевого указателя, и хотя результат преобразования nullptr
в тип указателя является значением нулевого указателя, сам nullptr
не имеет тип указателя, а тип std::nullptr_t
. Арифметика работает, если вы преобразуете nullptr
в тип указателя:
0 + (int*)nullptr;
(int*)nullptr - (int*)nullptr;
Может ли NULL-макрос быть нулевым?
Да, поскольку nullptr
является литералом с нулевым указателем.
Обратите внимание, что до C++ 11 все литералы нулевого указателя в C++ также были целыми литералами, поэтому этот плохой код: char c = NULL;
используется на практике. Если NULL
определяется как nullptr
, этот код больше не работает.
Ответ 3
Для добавления оба операнда должны иметь арифметический или неперечисленный тип перечисления, или один операнд должен быть указателем на полностью определенный тип объекта, а другой должен иметь интегральный или неперечисленный тип перечисления.
Для вычитания должно выполняться одно из следующих условий:
(2.1) оба операнда имеют арифметический или неперечисленный тип перечисления; или же
(2.2) оба операнда являются указателями на cv-квалификационные или cv-неквалифицированные версии одного и того же полностью определенного типа объекта; или же
(2.3) левый операнд является указателем на полностью определенный тип объекта, а правый операнд имеет интегральный или неперечисленный тип перечисления.
std::nullptr_t
является ничем из этого, поэтому std::nullptr
не может участвовать в аддитивных операциях.
Обратите внимание, что даже не могут принимать значения всех указателей. Например, значения указателя функции и значения указателя void не могут, даже если они могут быть нулевым значением указателя.
Ответ 4
Ключевое слово nullptr
обозначает литерал-указатель. Это prvalue
типа std::nullptr_t
. Существуют неявные преобразования от значения nullptr
к нулевому указателю любого типа указателя и любого указателя на тип члена. nullptr
сам по себе не является значением указателя или указателем. Таким образом, арифметические операции не применимы к nullptr
.