内容相同的std::string_view构成的unordered_map跨TU是否总能相等?
我有一个模拟过滤器功能的std::unordered_map,键与值均为std::string_view类型。现在想比较两个拥有完全相同键值对的过滤器实例:它们是否总能被判定为相等?
我的思路如下:编译器会尽可能将字节内容一致的const char*合并到二进制文件的同一存储位置,因此在单个翻译单元(TU)内,相同字符串字面量的地址始终相同。将这些地址传入std::string_view的构造函数后,由于std::string_view的operator==会对对象进行逐字节比较,只有当地址与长度完全匹配时,两个std::string_view才会被判定为相等。
但我有个疑问:如果在另一个翻译单元中实例化一个内容完全相同的过滤器,之后将多个目标文件链接在一起,编译器能否跨越翻译单元边界合并字符串字面量的存储位置?还是会因底层std::string_view指向的字符串字面量地址不同,导致过滤器的相等比较失败?
示例代码:
#include <unordered_map> #include <string_view> #include <cstdio> using filter_t = std::unordered_map<std::string_view, std::string_view>; int main() { filter_t myfilter = {{ "key1", "value"}, {"key2", "value2" }}; filter_t my_second_filter = {{ "key1", "value"}, {"key2", "value2" }}; if (my_second_filter == myfilter) { printf("filters are the same!\n"); } }
答案是:不能保证总能判定相等,核心原因在于字符串字面量的地址合并是编译器/链接器的可选优化行为,而非C++标准强制要求。
单个翻译单元内的情况
在同一个TU里,编译器通常会合并相同的字符串字面量,让它们指向同一块内存,对应的std::string_view地址和长度都一致,unordered_map的相等比较会成功——就像示例代码在单个TU中运行时会输出filters are the same!。跨翻译单元的情况
C++标准并没有要求链接器必须跨TU合并字符串字面量,不同工具链的行为存在差异:- GCC、Clang在默认优化级别下可能会跨TU合并,但关闭优化(如
-O0)或使用特殊编译选项时,可能不会执行该操作; - MSVC默认不会跨TU合并,需要手动开启
/GF选项才能启用字符串池化。
- GCC、Clang在默认优化级别下可能会跨TU合并,但关闭优化(如
如果跨TU的字符串字面量未被合并,两个std::string_view虽然内容相同,但指向的内存地址不同,此时std::string_view::operator==会返回false,进而导致两个unordered_map的相等比较失败——因为unordered_map的相等判断会逐一验证每个键值对的operator==结果。
- 解决方案
如果需要确保内容相同的过滤器一定能被判定相等,不要依赖字符串字面量的地址合并:- 改用
std::string作为键值类型,它的operator==是基于字符串内容比较,而非地址; - 为
std::unordered_map自定义哈希函数和相等判定逻辑,让哈希计算和相等比较基于string_view指向的字符串内容,而非视图本身的地址与长度(需手动指定unordered_map的模板参数)。
- 改用
内容的提问来源于stack exchange,提问作者glades

