实现std :: hash <t>

时间:2016-04-10 18:06:45

标签: c++ c++11 hash const unordered-set

我正在编写一个自定义OrderedTree课程,我想将其用作unordered_set的关键字。

我想在散列树时做一些事情:

  1. 懒惰地计算哈希并根据需要对其进行缓存(因为这可能是一项昂贵的操作),
  2. 也许平衡树。
  3. 这些操作都不会更改对象的语义相等或哈希值,但它们会修改某些私有字段。

    不幸的是,在OrderedTree内部尝试修改std::hash<Tree>::operator()中的所有成员时,似乎违反了unordered_set期望的const正确性。

    我可以将OrderedTreeunordered_set一起使用吗?如果是这样,怎么样?

    编辑:

    根据评论中的要求,最低限度的概念证明:

    #include <unordered_set>
    
    std::size_t hash_combine(std::size_t a, std::size_t b) {
      // TODO: Copy from boost source or something
      return 0;
    }
    
    struct Node {
      int value;
      Node *left, *right, *parent;
    
      std::size_t hash(std::size_t seed) const {
        if (left != nullptr)
          seed = left->hash(seed);
        std::hash<int> hasher;
        seed = hash_combine(seed, hasher(value));
        if (right != nullptr)
          seed = right->hash(seed);
        return seed;
      }
    };
    
    struct Tree {
    
      Tree(): hash_(0), root(nullptr) {}
    
      Node *root;
    
      std::size_t hash() const {
        if (hash_ == 0 && root != nullptr) {
          hash_ = root->hash(7);
        }
        return hash_;
      }
    
    private:
      std::size_t hash_;
    };
    
    namespace std {
      template<>
      struct hash<Tree> {
        std::size_t operator()(const Tree& t) const {
          return t.hash();
        }
      };
    }
    
    int main() {
      std::unordered_set<Tree> set;
    }
    

    当我尝试编译时,我得到:

    Sample.cc:31:13: error: cannot assign to non-static data member within const member function 'hash'
          hash_ = root->hash(7);
          ~~~~~ ^
    Sample.cc:29:15: note: member function 'Tree::hash' is declared const here
      std::size_t hash() const {
      ~~~~~~~~~~~~^~~~~~~~~~~~
    

1 个答案:

答案 0 :(得分:3)

可以保证std容器在执行const或逻辑const操作时只会调用const个成员。如果那些const操作是多读者安全的,那么容器也是如此;相反,如果不是,容器也不是。

哈希值和相等(或<在有序容器上)的不变性是在关联容器中的密钥类型中需要保证的东西。实际const给出了上述多读者保证,这非常有用。更重要的是,违反它会花费你将来使用它,和/或当某人假定const意味着不可变时会有微妙的后果。

你可以在内部仔细同步写操作,以保证多读者保证,或者你可以放弃。

要违反const,通常使用mutable。如果对象实际 const,而不仅仅是const的{​​{1}}视图,那么使用强制转换绕过const的{​​{1}}方法存在未定义的行为非 - const对象。

一般来说,在使用这种优化之前要小心;它可以轻松地增加代码复杂性(有bug,维护等),而不是增加速度。加速代码是可以替代的:确保将此标识为 slow 代码,并将此部分作为投资之前的瓶颈。如果要平衡哈希值,为什么要等待哈希?插入之前的平衡!