C++ map with custom key

Viewed 422

I have custom key for c++ map with '<' overloaded.

class CustomKey;

typedef map<CustomKey, int>     KeyValueMap;

class CustomKey {
    public:
    string      key1;
    int         key2;
    int         key3;

    bool operator < (const CustomKey & rhs) const {
        return ((key1 < rhs.key1)
             || ((key1 == rhs.key1) && (key2 < rhs.key2))
             || ((key2 == rhs.key2) && (key3 < rhs.key3)));
    }

    void display() const {
        cout << key1 << ":" << key2 <<":" << key3;
    }
};

I am able to add and display all five below keys.

void addDataToMap(KeyValueMap & valueMap)   {
    CustomKey   key1 = {"one", 100, 50};
    valueMap[key1] = 1;

    CustomKey   key2 = {"two", 200, 150};
    valueMap[key2] = 2;

    CustomKey   key3 = {"moreabc", 100, 100};
    valueMap[key3] = 27;

    CustomKey   key4 = {"less", 100, 150};
    valueMap[key4] = 30;

    CustomKey   key5 = {"morexyz", 100, 101};
    valueMap[key5] = 33;
}

void displayMap(const KeyValueMap & valueMap)   {
    KeyValueMap::const_iterator iter = valueMap.begin();
    while(iter != valueMap.end())   {
        iter->first.display();
        cout << " => " << iter->second << endl;
        iter++;
    }
}

But strangely search fails for below case. Different combination of addition in addDataToMap has different results.

void searchMap(const KeyValueMap & valueMap)    {
    CustomKey   key3 = {"morexyz", 100, 101};
    cout << "MapSize = " << valueMap.size() << endl;
    KeyValueMap::const_iterator iter = valueMap.find(key3);
    if(iter == valueMap.end())  {
        cout << "NotFound" << endl;
        return;
    }

    cout << iter->second << endl;
}

int main()  {
    KeyValueMap     valueMap;

    addDataToMap(valueMap);

    displayMap(valueMap);

    searchMap(valueMap);

    cout << endl;
    return 0;
}

Output:-

one:100:50 => 1
moreabc:100:100 => 27
morexyz:100:101 => 33
less:100:150 => 30
two:200:150 => 2
MapSize = 5
NotFound

With '<' logic remaining same, i believed, anything that is added to map will shall be found as well.

2 Answers

Use the operator < defined like

#include <tuple>

//...

bool operator < (const CustomKey & rhs) const {
    return std::tie( key1, key2, key3 ) < std::tie( rhs.key1, rhs.key2, rhs.key3 );
}

Such a definition of the operator is clear and is not error-prone.

Otherwise your operator does not satisfy the requirement to provide the strict weak ordering relation.

Try to consider the case that key1 > rhs.key1 and key2 == rhs.key2 and key3 < rhs.key3, the operator < would return true which is not expected.

You could keep (key1 == rhs.key1) in the last brance of the operator || in the operator <. e.g.

bool operator < (const CustomKey & rhs) const {
    return ((key1 < rhs.key1) || 
            ((key1 == rhs.key1) && (key2 < rhs.key2)) || 
            ((key1 == rhs.key1) && (key2 == rhs.key2) && (key3 < rhs.key3)));
}

LIVE

Related