Когда можно сравнить два указателя?

Существует так много вопросов о сравнении двух указателей, но я не нашел ни одного вопроса о том, подходят ли два типа для сравнения указателей. Данный

A* a;
B* b;

Я хочу знать, действительно ли выражение a @ b, где @ является одним из _4 _, _ 5 _, _ 6 _, _ 7 _, _ 8 _, _ 9_ (я не возражаю против nullptr_t или любого другого типа, который может быть неявно преобразован в указатель). Это когда A, B

  • равный?
  • равны кроме резюме?
  • в той же иерархии классов?
  • ...?

Ничего не нашел в std::type_traits. Я всегда могу провести свой собственный тест SFINAE, но я ищу правила, чтобы применять их напрямую. Думаю, компилятору будет проще, не так ли?

РЕДАКТИРОВАТЬ Чтобы еще раз прояснить: я сравниваю указатели, а не объекты, на которые они указывают. Я хочу знать заранее, когда a @ b выдаст ошибку компилятора, а не каково будет его значение (истинное, ложное или неуказанное).


person iavr    schedule 18.03.2014    source источник


Ответы (2)


Стандарт C ++

5.9 Операторы отношения

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

- Если два указателя p и q одного типа указывают на один и тот же объект или функцию, или оба указывают на один за концом одного и того же массива, или оба равны нулю, то оба p ‹= q и p> = q дают значение true и p ‹q и p› q возвращают false.

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

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

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

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

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

person Spook    schedule 18.03.2014
comment
Итак: выражение a @ b никогда не выдаст ошибку компилятора, независимо от того, указан результат или нет, верно? - person iavr; 18.03.2014
comment
Да; компилятор жаловаться не будет. Неопределенное поведение дает возможность оптимизировать неочевидными способами. - person Jonathan Leffler; 18.03.2014
comment
@Jonathan: Да, компилятор не будет жаловаться - неправда ... вы не можете сравнивать указатели на несвязанные типы без ошибки времени компиляции. Неопределенное поведение ... - Spook описывает неопределенное поведение, что в основном означает, что компилятор мог поместить любой из объектов, на которые указывает указатель, по более высокому адресу памяти, а не Undefined, который означало бы, что сравнение не может быть выполнено без риска сбоя или иного повреждения состояния программы. - person Tony Delroy; 18.03.2014
comment
Указатели ... одного и того же типа (после преобразования указателя) можно сравнить +1 для этого, но это половина вопроса, другая половина - можно ли сравнивать указатели разных типов .... - person Tony Delroy; 18.03.2014
comment
Они должны быть совместимы, то есть один конвертируемый в другой с помощью стандартных преобразований указателей. - person n. 1.8e9-where's-my-share m.; 18.03.2014
comment
Хорошо, ситуация становится настолько сложной, что, возможно, мне вообще не следует проводить какие-либо тесты и просто позволить компилятору жаловаться ... Или, если я провожу тест, SFINAE на decltype(a @ b), возможно, быстрее и менее подвержен ошибкам, чем кодирует все эти правила? - person iavr; 18.03.2014
comment
@Spook Это сделано для того, чтобы предоставить операторы сравнения для итераторов. Но теперь я вижу в правилах, что на самом деле двух типов недостаточно даже для того, чтобы знать, выдаст ли компилятор ошибку; требуется дополнительная информация. Поэтому я думаю, что мне не следует проводить никаких тестов: просто определите мой оператор сравнения и позвольте компилятору проверить, можно ли сравнивать базовые указатели. Может, это все-таки был глупый вопрос. - person iavr; 18.03.2014
comment
@ Spook / @ n.m. Кстати, а какие бывают стандартные преобразования указателей? - person iavr; 18.03.2014
comment
@iavr В стандарте C ++ по этому поводу есть несколько разделов. Здесь вы можете получить почти последний стандарт C ++ 11: open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf - person Spook; 18.03.2014

Эти операторы сравнения всегда «действительны» в том смысле, что вы всегда можете их использовать. Но результаты обычно не будут значимыми или полезными.

== и != по сути скажут вам, относятся ли a и b к одному и тому же объекту. Если a == b, то изменение * a повлияет на * b и наоборот.

>, <, >= и <= сообщат вам, где находятся адреса памяти относительно друг друга. Обычно эта информация не имеет отношения к функциональности вашей программы и в большинстве случаев непредсказуема. Однако на ум приходит один пример, в котором вы могли бы его использовать, если вы знаете, что a и b указывают на член одного и того же массива. В этом случае a < b сообщит вам, стоит ли объект *a перед *b в массиве.

person karadoc    schedule 18.03.2014
comment
Эти операторы сравнения всегда «действительны» в том смысле, что вы всегда можете их использовать. - это неправда ... вы не можете сравнивать A* с B*, когда A и B не связаны между собой ... вы получите ошибку компилятора. - person Tony Delroy; 18.03.2014