std::string_view 编译时散列

Posted

技术标签:

【中文标题】std::string_view 编译时散列【英文标题】:std::string_view compile time hashing 【发布时间】:2016-06-09 08:37:07 【问题描述】:

似乎 C++17 string_view 的 std::hash functions 不是 constexpr 的。

在我看来,绑定到 const char[] 的字符串视图可以在编译时进行散列处理(这会很不错),或者有什么可以防止这种情况发生?

【问题讨论】:

我认为hash<T>::operator() 中的任何一个都不是 constexpr,即使对于整数类型也是如此(或者至少我在 n4567 中找不到任何提及 constexpr 哈希的内容。) 啊我明白了,没注意到,不知道为什么。 【参考方案1】:

从 C++14 开始(参见 17.6.3.4 哈希要求,表 26),我们有:

返回的值应仅取决于持续时间的参数 k 的程序。 [注意:因此表达式 h(k) 的所有计算 相同的 k 值产生相同的结果对于给定的执行 程序。 -- 尾注]

两个different executions can give different hashes:

哈希函数只需要产生相同的结果 相同的输入在一个程序的单个执行中; 这允许 防止冲突 DoS 攻击的加盐哈希。

This behaviour is useful 缓解hash collision-based DoS attacks。

详情

以下是 C++17 标准中关于 Hash 概念要求的措辞:

返回的值应仅取决于参数 k 在项目期间。 [注:因此所有 表达式 h(k) 的评估具有相同的 k 的值产生相同的结果 程序的给定执行。 ——尾注]

它没有明确说明有关随机散列的任何内容。 std::hash 文本不强制也不排除随机散列。

历史

这是N3242 2011-02-28 的草案,其中没有提到“在计划期间”:

不应抛出异常。返回的值将取决于 关于论点 k。 [注意:因此表达式 h(k) 的所有计算 使用相同的 k 值产生相同的结果。 ——尾注

我们可以看到添加了“在程序期间”“对于程序的给定执行”作为“2291. std::hash is vulnerable to collision DoS attack”的分辨率。

在实践中

AFAIU,std::hash 没有实现随机散列,但您可以编写自己的 my::secure_hash

【讨论】:

不幸的是,最后一句话根本不是真的。该标准确实要求该值仅取决于给定程序执行的参数,这是正确的。但是,这是因为某些实现只是将指针转换为哈希值。其他实现(例如 GCC)在运行时使用带有内置常量种子的 FNV1 可证明按字节进行散列,因此实际上不存在随机散列之类的东西。因此,该标准为我们提供了两个世界中最糟糕的一个:没有可预测的输出值,没有 constexpr,同时没有可靠不可预测的输出值。 @Damon:我想说这还不错。该标准为您提供的是使用不可预测的散列编写自己的my::secure_hash 和使用constexpr 能力编写自己的my::fast_hash 的能力。它使实现能够对std::hash 使用不可预测的散列。

以上是关于std::string_view 编译时散列的主要内容,如果未能解决你的问题,请参考以下文章

Boost.Container flat_map 和 std::string_view

哈希<std::string> 与哈希<std::string_view>

除了 std::string_view 方法之外,std::string_view 比 char* 有啥优势吗?

带有 C 函数的 std::string_view

将 std::string_view 返回到 const char * [重复]

如何将 boost::string_view 转换为 std::string_view?