【问题标题】:Storing Key Hash in Class for efficiency在类中存储密钥哈希以提高效率
【发布时间】:2017-10-19 00:40:46
【问题描述】:

我有一个类作为特定不可变信息 X 的容器,它是其对象的标识。这个类还有一些额外的数据,但它们对对象的比较没有任何影响。如果a.X==b.X 就是这样。这些对象保存在一个哈希表中,例如 C++ 中的unordered_mapunordered_set,并且在操作期间有大量的查找。并且定义散列函数的一般方式 - 据我观察 - 在每次查找时计算散列(这通常是合乎逻辑的,因为类的内容可能已经改变)。

我的问题是:如果散列数据在对象的生命周期内保证为 const。将_object_hash 数据作为类成员并提供哈希函数以仅比较a._object_hash==b._object_hash 是一种好习惯吗?或者在 C++ std.容器或通常在 OOP 中。

【问题讨论】:

  • 只要在将对象保存到磁盘/网络时不序列化哈希值就可以了。在程序的 2 次单独运行中,允许相同对象的哈希值不同。
  • @RichardHodges 即使散列数据没有改变?我是说;例如,如果我只对一个字符串进行散列,散列是否需要每次运行都更改?即使我序列化对象,相同的字符串和哈希数据也会被反序列化,这很好。
  • 不,这不好。该标准明确指出,后续运行的哈希码可以计算不同的值。因此,如果您反序列化 a,然后使用与 a 相同的构造函数参数创建 b,则允许 a 和 b 计算不同的哈希码。
  • @RichardHodges 这是我一直在寻找的信息。您能否将我指向文档以阅读有关标准的更多信息。并提供此作为答案。

标签: c++ oop hash


【解决方案1】:

你的方法很好,前提是:

  • 如果operator==(a, b),则保证a.hash_code() == b.hash_code()

  • 在将对象序列化到磁盘、网络或其他任何地方时,不要保存 hash_code。

  • 如果你加载/反序列化对象,你会重新计算哈希

对于程序的任何一次运行,std::hash(x) 保证在每次调用不可变 x 时返回相同的值。但是,不能保证同一程序的后续运行会产生相同的结果。

因此,防止预先计算的哈希码的序列化/反序列化很重要。

您可能需要考虑包装器

template<class T> 
struct hashed: T
{
    hashed(T&& t) 
    : T(std::move(t))
    , hash_code_(std::hash<T>()(*this)) {}


    std::size_t hash_code() const
    {
        return hash_code_;
    }
private:
    std::size_t hash_code_;
};

namespace std {

    template<class T> 
    struct hash<hashed<T>>
    {
        auto operator()(hashed<T> const& t) const {
            return t.hash_code();
        }
    }
}

参考:http://en.cppreference.com/w/cpp/utility/hash

特别看:

哈希函数只需要在程序的单次执行中为相同的输入产生相同的结果;这允许防止冲突 DoS 攻击的加盐哈希。 (c++14 起)

【讨论】:

    猜你喜欢
    • 2014-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 2018-06-01
    相关资源
    最近更新 更多