为何当T为指针类型时std::unordered_multiset的==运算符返回错误结果?
编译器Bug还是使用错误?自定义指针哈希/相等仿函数后unordered_multiset比较不生效
我为指针类型提供了哈希和相等仿函数,但unordered_multiset的相等比较似乎不生效,还特意写了自定义模板容器测试这些仿函数。
哈希仿函数
class CharPtHash { private: using pChar = char*; public: size_t operator()(const pChar& c) const { std::hash<char> hasher; if (c == nullptr) { return 0; } return hasher(*c); } };
相等仿函数
class CharPtEqual { private: using pChar = char*; public: bool operator()(const pChar& lhs, const pChar& rhs)const { if (lhs == rhs) { return true; } else if (lhs==nullptr || rhs==nullptr) { return false; } return *lhs == *rhs; } };
测试代码
#include <iostream> #include <unordered_set> using namespace std; // 此处省略上述哈希/相等仿函数定义 // 自定义unordered_multiset输出重载(假设用户实现了此部分) template <typename T, typename Hash, typename Equal> ostream& operator<<(ostream& os, const unordered_multiset<T, Hash, Equal>& ms) { os << "{ "; for (const auto& elem : ms) { os << *elem << ", "; } os << "\b\b }"; return os; } int main() { cout << "Testing unordered_multiset with keys being simple types:\n"; unordered_multiset<char> sA1({ 'a','b','c' }); unordered_multiset<char> sA2({ 'a','c','b' }); cout << "Values: " << endl << sA1 << endl << sA2 << endl; cout << (sA1 == sA2 ? "Equal" : "Not Equal"); cout << endl; cout << "Testing unordered_multiset with keys being pointers to simple types:\n"; char** c1 = new char* [3]{ new char('a'), new char('b'), new char('c') }; char** c2 = new char* [3]{ new char('a'), new char('c'), new char('b') }; unordered_multiset<char*,CharPtHash,CharPtEqual> sB1; unordered_multiset<char*,CharPtHash,CharPtEqual> sB2; sB1.insert(c1[0]); sB1.insert(c1[1]); sB1.insert(c1[2]); sB2.insert(c2[0]); sB2.insert(c2[1]); sB2.insert(c2[2]); cout << "Values: " << endl << sB1 << endl << sB2 << endl; cout << (sB1 == sB2 ? "Equal" : "Not Equal"); cout << endl; // 手动释放内存 for (int i = 0; i < 3; ++i) { delete c1[i]; delete c2[i]; } delete[] c1; delete[] c2; cin.get(); }
输出结果
Testing unordered_multiset with keys being simple types: Values: { a, b, c } { a, c, b } Equal Testing unordered_multiset with keys being pointers to simple types: Values: { a, b, c } { a, c, b } Not Equal
这不是你的使用错误,而是Visual Studio标准库中unordered_multiset的operator==实现不符合C++标准的问题。
根据C++标准,无序容器的相等比较仅需满足两个条件:容器大小相同,且每个等价元素的数量一致(等价性由自定义相等谓词定义),与元素的存储顺序无关。但Visual Studio的实现中,unordered_multiset的operator==会按迭代器顺序逐个比较元素,导致元素顺序不同但等价数量一致的容器被判定为不相等。
你可以通过手动验证等价元素数量的方式替代默认的operator==,示例如下:
bool areEqual(const unordered_multiset<char*, CharPtHash, CharPtEqual>& a, const unordered_multiset<char*, CharPtHash, CharPtEqual>& b) { if (a.size() != b.size()) return false; for (const auto& elem : a) { if (a.count(elem) != b.count(elem)) { return false; } } return true; }
调用此函数即可得到符合标准的相等判断结果。
另外,你的哈希与相等仿函数满足C++标准要求的一致性(相等的元素哈希值必然相同),这部分实现是正确的。
内容的提问来源于stack exchange,提问作者Software Carpenter
相关产品推荐
相关产品推荐

