Разрешены ли указатели как ключи в заказанных контейнерах STL? - PullRequest
7 голосов
/ 06 февраля 2011

Есть этот другой вопрос, спрашивающий о том, как предполагается интерпретировать сравнение указателей по отношению к стандарту C ++.

Поэтому мне было интересно, что скажет стандарт C ++ об использовании указателей в качестве ключейв контейнерах с заказанной стандартной библиотекой (STL) - то есть один может иметь

std::map<T1*, T2>

, и это связано со спецификацией std::less или builtin operator <?

Ответы [ 4 ]

11 голосов
/ 06 февраля 2011

Да, потому что он использует std::less, что необходимо для получения итогового заказа, даже если < нет. (< будет разрешено рассматривать разные указатели из разных последовательностей как равные, что приведет к странному поведению map и т. Д., Если вы вставите указатели из разных последовательностей).

3 голосов
/ 06 декабря 2012

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

Это голос горького опыта.Я сделал это с проектом отладчика, где у меня были контейнеры, заполненные символами C ++.Когда мне нужно было сортировать символы, я получал символы, которые отличаются друг от друга, но имеют одинаковые имена (например, перегруженные функции) и идентичны во всех других отношениях.Итак, в этом случае я сравнил их в крайнем случае по адресу символа объекта.Я столкнулся с несколькими ошибками, которые были явно недетерминированными, где недетерминизм был вызван именно этим явлением.Иногда потребовалось более 10 или 15 попыток воспроизвести проблемы.В конце концов я потратил время на устранение сортировки по адресам, и это избавило меня от многих проблем в долгосрочной перспективе.Но каждый раз, когда я делаю это, я чувствую, что это ошибка.

0 голосов
/ 06 февраля 2011

«Они могут быть действительными, но не верны» - вот ответ, который я бы дал.

Очевидно, что существует проблема сравнимости, которую вы поднимаете, но причина, по которой вы не хотите этого делать, заключается в отсутствии управления ссылками для «ванильных» указателей. Очень легко удалить объект, не удаляя его из контейнера, что приведет к неверному указателю и нарушению доступа при следующем обращении к нему.

0 голосов
/ 06 февраля 2011

Да.Указатели сравнимы с помощью оператора <(). </p>

Если указатели не указывают на элементы одного и того же массива или элементы в одном и том же объекте, стандарт c ++ говорит, что поведение не определено [expr.rel].

Стандарт говорит, что неопределенное поведение означает, что его реализация определена [defns.unspecified].

Если ваш компилятор гарантирует строгий слабый порядок указателей, вы можете использовать любой указатель с ассоциативными контейнерами.

Большинство компиляторов выполняют сравнение указателей путем сравнения адресов памяти.На большинстве архитектур это сравнение образует строгий слабый порядок.

Поэтому в качестве ключей безопасно использовать указатели.

...