Содержимое boost::shared_ptr как ключа для set?

#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, не говоря уже о том, что функциональный подход практически нечитаем.