Использование std:: less с nullptr

Всегда ли выполняется утверждение в следующем фрагменте кода?

std::less<Object *> lessPtr;
Object * o = new Object();
assert(lessPtr (o, nullptr) == false);

Ответ 1

Введение

Этот вопрос действительно сводится к тому, что использование менее реляционного оператора по типам указателей, где один операнд является nullptr, даст ожидаемый результат; что, к сожалению, не так.

Результат не указан.

Примечание: Имейте в виду, что std::less гарантирует общий порядок; что даже если результат при использовании объекта функции не задан, он должен давать то же самое неуказанное значение для каждого вызова.


Что означает Международный стандарт (N3337)?

5.9p2 Реляционные операторы [expr.rel]

Указатели на объекты или функции одного и того же типа (после конверсий указателей) можно сравнить с результатом, определяемым следующим образом:

     
  •   
  • Если два указателя p и q того же типа указывают на один и тот же объект или функцию, либо оба указывают один за концом одного и того же массива, либо оба являются нулевыми, то p<=q и p>=q оба выхода true и p<q и p>q дают false.

      
  • Если два указателя p и q того же типа указывают на разные объекты, которые не являются членами одного и того же объекта или элементов одного и того же массива или с разными функциями, или если только один из них null, результаты p<q, p>q, p<=q и p>=q не определены.

      
  • Если два указателя указывают на нестатические элементы данных одного и того же объекта или на подобъекты или элементы массива таких элементов, рекурсивно, указатель на более поздний объявленный элемент сравнивается больше, если два члена имеют одинаковый доступ (раздел 11) и при условии, что их класс не является объединением.

      
  • Если два указателя указывают на нестатические элементы данных одного и того же объекта с различным контролем доступа (раздел 11), результат не указан.

      
  • Если два указателя указывают на нестатические элементы данных одного и того же объекта объединения, они сравнивают одинаковые значения (после преобразования в void*, если необходимо). Если два указателя указывают на элементы одного массива или один за концом массива, указатель на объект с более высоким индексом сравнивается выше.

      
  • Другие сравнения указателей не указаны.

      

20.8.5p8 Сравнение [comparision]

Для шаблонов greater, less, greater_equal и less_equal специализации для любого типа указателя дают полный порядок, даже если встроенные операторы <, >, <=, >= не.


Итак, что такое стандарт, который действительно говорит?

T * p = new T;
T * q = nullptr;


Каков вердикт для p < q?
Поскольку p и q не указывают на разные элементы одного и того же массива (включая элемент один за последним элементом массива), и оба не указывают на нестатические элементы данных одного и того же объекта; результат при выполнении p < qp > q) не указан.

bool a = p < q;  // unspecified
bool b = p < q;  // unspecified

assert (a == b); // can fire


Как насчет std::less?
Однако при использовании std::less нам гарантируется полный порядок, что фактически означает, что нижеприведенное утверждение не может fire (standard-20.8.5p8).

std::less<T*> comp;

bool a = comp (p, q);  // unspecified
bool b = comp (p, q);  // unspecified

assert (a == b);       // can not fire

Ответ 2

Нет, порядок нулевого указателя относительно любого ненулевого указателя не указан.

Результат операторов сравнения не указан, если операнды "указывают на разные объекты, которые не являются членами одного и того же объекта или элементов одного и того же массива или с разными функциями, или если только один из них является нулевым".

std::less и друзья расширяют это, чтобы указать, что существует общий порядок, но не указывать, где в этом порядке присутствуют нулевые указатели. Таким образом, он гарантировал, что null будет последовательно либо больше, либо меньше любого заданного непустого указателя. Но он не указан как меньше или больше, чем все ненулевые указатели.