Home > OS >  Why does the == operator of std::unordered_multiset<T> returns wrong result when T is a pointe
Why does the == operator of std::unordered_multiset<T> returns wrong result when T is a pointe

Time:11-14

Is this a bug, or am I doing something wrong? I already tried providing hashing and equality functors for the pointer type, but it doesn't seem to work. I even tried creating my own miniature template container just to test the functors.

Hashing functor:

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);
    }
};

Equality:

class CharPtEqual
{
private:
    using pChar = char*;
public:
    bool operator()(const pChar& lhs, const pChar& rhs)const
    {

        if (lhs == rhs)//not sure of nullptr is equal to itself.
        {
            return true;
        }
        else if (lhs==nullptr || rhs==nullptr)
        {
            return false;
        }
        return *lhs == *rhs;
    }
};

Main:

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;

    cin.get();
}

I tried compiling it to c 20 and c 14 using Visual Studio 2022.

This is the output:

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

CodePudding user response:

Well, my previous answer was completely wrong: as far as I can tell, your Hash and Pred are correct. However, the issue is somewhere else. operator == for std::unordered_multiset uses std::is_permutation() to perform comparison internally and doesn't provide any comparison function that algorithm, so default operator == for that type (in this case char*) is used. There is UB due to that I think, but I don't really understand the phrasing there.

To be fair, this looks like an oversight in standard. operator == for std::unordered_multimap doesn't allow comparing different types of maps, so it should be possible to pass Pred instance to std::is_permutation. Or maybe there is a reason to have it that way, but I don't see it.

  • Related