为啥标准不提供通过内容检查散列 c 字符串的专业化
Posted
技术标签:
【中文标题】为啥标准不提供通过内容检查散列 c 字符串的专业化【英文标题】:Why standard does not provide specialization for hashing c strings with content examination为什么标准不提供通过内容检查散列 c 字符串的专业化 【发布时间】:2020-08-15 21:42:29 【问题描述】:我正在阅读有关散列的信息,我在here 中找到了以下语句:
C 字符串没有特化。
std::hash<const char*>
生成指针值(内存地址)的哈希值,它不检查任何字符数组的内容。
为什么没有对检查其内容的 C 字符串进行哈希处理的机制?
我正在浏览std::string_view
的代码,似乎可以方便地同时涵盖std::string
和std::string_view
。
编辑
感谢 cmets。我想我不是很清楚。我应该问为什么没有功能来散列 c 字符串并将其长度作为参数? hash(const char* data, size_t size)
将处理 nul,而不是 nul 终止的 c 字符串。
【问题讨论】:
const char*
不必指向以 nul 结尾的字符串...
@Jarod42 不知怎的,这并没有阻止提供operator<<(ostream&, const char*)
过载。
std::hash<std::string>(foo)
有什么问题(foo
是char const *
)?
顺便说一句:“std::char_traits
中有许多有用的操作可以(或可能已经)在std::string
和std::string_view
之间共享,但由于某种原因,散列是一个都没有。我想知道为什么。” -- 这与你问的问题不同。您问为什么标准 hasing 不处理 C 风格的字符串,而这个其他问题相当于问为什么散列不被视为命名要求的一部分 CharTraits。答案是相互独立的。请一次只回答一个问题。
第三个问题,这可能是您真正的问题,是如何使用标准工具计算 C 样式字符串的哈希,而无需触及实现细节。这是三个问题中最容易回答的问题,所以如果这是你真正的问题,很遗憾你在评论中隐藏它作为暗示(你应该在一个新问题中提出,如果这确实是你的问题有兴趣,如果你找不到它已经在这里回答)。
【参考方案1】:
不可能进行特化,因为“C 字符串”只是指针,暗示它们是以空值结尾的。 const char *
也可以是指向某些原始字节数据的指针,不一定是 C 字符串。您根本无法假设所有 const char *
都以空值结尾。
如果您使用std::string
,您对std::string_view
的建议不是一个好主意,因为当关联的std::string
被破坏时,std::string_view
将失效。
您的建议只有在您可以保证关联的 C 字符串或 std::string
只要 std::string_view
存储在地图中就保持活动状态时才有效。
程序员有责任确保生成的字符串视图不会超过字符串。
(见std::basic_string<CharT,Traits,Allocator>::operator basic_string_view
)
【讨论】:
这些考虑并没有阻止标准库提供operator<<(ostream&, const char*)
重载,该重载假定一个以 nul 结尾的字符串。
@IgorTandetnik 运算符重载用于const void *
,而不是专门用于const char *
。见en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt。我想这个重载是标准库中的不一致。但如果不是因为这个重载,你就不能通过<<
打印字符串文字,所以把它放在这里很重要。
还有专门针对const char*
的an overload,它会打印指针指向的实际字符串(假定为nul 终止)。鉴于此,我不太明白您要表达的意思。
@IgorTandetnik 哦,好吧,我没有看到在标头本身中定义了更多的重载。不过,它正在比较苹果和橙子。当通过流打印时,假设const char *
是字符串文字是有意义的,但std::hash
不是。
@IgorTandetnik 在旁注中,哈希映射无论如何都不是字符串的良好关联容器。散列长字符串可能非常昂贵,而不是仅比较 std::map
中的前几个字符的字典顺序。更好的是 trie 或 radix 树。以上是关于为啥标准不提供通过内容检查散列 c 字符串的专业化的主要内容,如果未能解决你的问题,请参考以下文章
为啥 MISRA-C 检查器提供错误检查 STM32 HAL?