CMapStringToString迁移到std::map<CString,CString>收益及编译问题咨询
问题解答
一、迁移到std::map<CString, CString>的实际收益
- 通用性更强:
std::map是C标准库组件,代码逻辑可以直接复用在非MFC项目中,后续如果有跨平台迁移需求也更方便,所有熟悉C标准库的开发人员都能直接维护,不需要额外学习MFC专有容器的API。 - 接口设计更规范:std容器的接口统一符合STL设计规范,可以直接配合所有STL算法使用,不需要额外做适配。
- 类型安全性更高:MFC的
CMap系列容器隐式转换多,运行时容易出现未定义行为;std容器是强类型,更多错误可以在编译阶段发现,同时VS的调试可视化工具对STL容器的支持也更完善,排查问题更方便。 - 性能表现更稳定:
std::map的红黑树实现性能可预期,不同版本VS下表现一致;MFC的CMap实现会随MFC版本变动,性能波动更大。
二、std::unordered_map编译报错的原因
std::unordered_map是哈希表实现,要求键类型必须有对应的std::hash特化实现来计算哈希值,而CString是MFC/ATL的专有字符串类,C++标准库并没有默认提供std::hash<CString>的特化,所以编译器在实例化std::unordered_map<CString, CString>的时候找不到可用的哈希函数,就会抛出你遇到的C2064编译错误。
而std::map是基于红黑树的有序容器,只要求键类型支持operator<比较大小,CString本身已经重载了operator<运算符,所以不需要额外实现就可以正常编译。
三、解决方案
你可以根据自己的需求选择以下任意一种方案:
- 继续使用
std::map<CString, CString>:如果你的数据量不大,find、[]、clear三类操作的性能完全可以满足业务需求,这是改造成本最低的方案,不需要修改其他业务代码。 - 特化
std::hash<CString>让unordered_map支持CString键:
将以下代码添加到你定义unordered_map的头文件中即可:
#include <string_view> template<> struct std::hash<CString> { size_t operator()(const CString& str) const noexcept { // 项目使用多字节字符集时,将wstring_view替换为string_view即可 return std::hash<std::wstring_view>{}(std::wstring_view(str.GetString(), str.GetLength())); } };
该实现直接基于CString的原生内容计算哈希,没有额外的字符串拷贝开销,性能表现优异。
3. 显式指定unordered_map的哈希函数参数:
如果不想修改std命名空间的特化,也可以自定义哈希结构体,在定义容器时显式传入:
#include <string_view> struct CStringHash { size_t operator()(const CString& str) const noexcept { return std::hash<std::wstring_view>{}(std::wstring_view(str.GetString(), str.GetLength())); } }; // 容器定义改为如下形式 std::unordered_map<CString, CString, CStringHash> your_map_variable;
内容的提问来源于stack exchange,提问作者Andrew Truckle
相关产品推荐
相关产品推荐

