#c #boost #set
#c #boost #установить
Вопрос:
Я хотел бы сохранить серию указателей в std::unordered_set
. Я бы хотел, чтобы хэш-функция основывалась не на адресе памяти, а на некоторых значениях, содержащихся в реальном объекте, на который ссылается указатель.
например ( using std
и boost
пространства имен для удобства чтения)
class MyClass {
...
//some values I want to use as the key for the hash
double a;
int b;
int c;
}
typedef shared_ptr<MyClass> MyClassPtr;
set<MyClassPtr> mySet;
Я не беспокоюсь об объединении фактических значений хэша (нашел ответ здесь:http://www.boost.org/doc/libs/1_47_0/doc/html/hash/combine.html ), а скорее разыменование shared_ptr
для получения ключей.
Другая проблема, которую я испытываю, заключается в том, что для == operator
уже определено boost::shared_ptr
, и мне было интересно, вызовет ли это проблемы с моим подходом? Мне нужно было бы проверить равенство по отношению к объекту, а не к указателю.
Сохранение указателей в set, потому что несколько других частей кода ссылаются на объекты через свои собственные указатели. Также приветствуются любые альтернативные подходы.
Спасибо
Комментарии:
1. Ты имеешь в виду
unordered_set<MyClassPtr>
?std::set
использует строгий слабый порядок, а не хэш-значения.
Ответ №1:
В чем проблема? Определите хэш-функцию и равенство и вперед:
struct MyClassHash
{
inline std::size_t operator()(const MyClassPtr amp; p)
{
return 4; // prone to hash collisions, improve on this
}
};
struct MyClassEqual
{
inline bool operator()(const MyClassPtr amp; p, const MyClassPtr amp; q)
{
return false; // implement
}
};
typedef std::unordered_set<MyClassPtr, MyClassHash, MyClassEqual> MySet;
Обратите внимание, что два функтора (хэш и равенство) должны быть записаны как классы; свободные функции не работают. (В контейнере хранится частный экземпляр функторов.) Это несколько раздражает, но поскольку вы будете делать это только один раз, это не должно быть так плохо.
Обычно я бы рекомендовал специализироваться на std::hash
и std::equals
, но я бы не решился делать это с чем-то таким общим, как общий указатель, поскольку это может легко запутать других, которые не ожидают этих специализаций.
Комментарии:
1. 1 для
// prone to hash collisions, improve on this
. (Хотя это гарантированно случайный код!)2. Почему не функции?
typedef std::unordered_set<MyClassPtr, std::size_t (*)(const MyClassPtr amp; p), bool (*)(const MyClassPtr amp; p, const MyClassPtr amp; q)> MySet; MySet m(42, amp;my_hash_func, amp;my_pred_func);
3. @dalle: Хм, кажется, я пробовал это, но не смог заставить это работать… в любом случае, это означает, что функтор не может быть сконструирован по умолчанию, и вы должны постоянно поддерживать этот неуклюжий конструктор. При оптимизации с пустой базой подход, основанный на классах, не должен быть хуже.
4. Я согласен, подход на основе функтора, вероятно, был бы быстрее в любом случае из-за встраивания и тому подобного,
5. @dalle, не говоря уже о том, что функциональный подход практически нечитаем.