You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内容相同的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选项才能启用字符串池化。

如果跨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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 10:50:24