我正在编写一个自定义OrderedTree
课程,我想将其用作unordered_set
的关键字。
我想在散列树时做一些事情:
这些操作都不会更改对象的语义相等或哈希值,但它们会修改某些私有字段。
不幸的是,在OrderedTree
内部尝试修改std::hash<Tree>::operator()
中的所有成员时,似乎违反了unordered_set
期望的const正确性。
我可以将OrderedTree
与unordered_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 {
~~~~~~~~~~~~^~~~~~~~~~~~
答案 0 :(得分:3)
可以保证std容器在执行const
或逻辑const
操作时只会调用const
个成员。如果那些const
操作是多读者安全的,那么容器也是如此;相反,如果不是,容器也不是。
哈希值和相等(或<
在有序容器上)的不变性是仅在关联容器中的密钥类型中需要保证的东西。实际const
给出了上述多读者保证,这非常有用。更重要的是,违反它会花费你将来使用它,和/或当某人假定const
意味着不可变时会有微妙的后果。
你可以在内部仔细同步写操作,以保证多读者保证,或者你可以放弃。
要违反const
,通常使用mutable
。如果对象实际 const
,而不仅仅是const
的{{1}}视图,那么使用强制转换绕过const
的{{1}}方法存在未定义的行为非 - const
对象。
一般来说,在使用这种优化之前要小心;它可以轻松地增加代码复杂性(有bug,维护等),而不是增加速度。加速代码是可以替代的:确保将此标识为 slow 代码,并将此部分作为投资之前的瓶颈。如果要平衡哈希值,为什么要等待哈希?插入之前的平衡!