'Custom sort and key uniqueness in std::map C++

Consider the follow std::map code. The idea is to sort keys based only a double value even though the key contains more information. In the custom sort used for the map, there are 3 test conditions the first of which does not work as expected. I would like to understand why before I assume the next two actually behave as I expect them too.

Test choices 2 and 3 explicit that I do not care about the content of s_Rule (some pointer containing information) for sorting purposes but how does that also break the key mechanism of map. In fact, 2 and 3 are literally the same since if double == double and ptr == ptr than the key is obviously the same.

This may (or may not) be related to question : How can I declare a custom sort function on std::map declaration? in which Simon9987 asks at the end why sort has broken the std::find function

class s_Rule
{
    int x;
    s_Rule() : x(0) {} // irrelevant content for question
}

typedef std::pair<double, s_Rule*> ruleSavedData;
struct sortByDouble
{
    bool operator()(const ruleSavedData& a, const ruleSavedData& b) const
    {
        return a.first < b.first; //                // not ok
//        return a.first < b.first || (a.first == b.first && a.second != b.second); // ok
//        return a.first <= b.first;                  // ok
    }
};
typedef std::map<ruleSavedData, std::tuple<int, int, int>, sortByDouble> t_splitRulePool;

t_splitRulePool _splitRulePool;
    
    

auto test1 = new s_Rule();
auto test2 = new s_Rule();
auto test3 = new s_Rule();
const auto pp1 = ruleSavedData(687.00, test1);
_splitRulePool[pp1] = std::tuple<int,int,int>({1, 0, 0});

for (const auto& sr : _splitRulePool)
    std::cout << sr.first.first << " with rule: " << sr.first.second << " and value " << std::get<0>(sr.second) << std::endl;

// Output: 687 with rule: 000001F9B60509E0 and value 1

const auto pp2 = ruleSavedData(688.00, test2);
_splitRulePool[pp2] = std::tuple<int, int, int>({ 2, 0, 0 });

for (const auto& sr : _splitRulePool)
    std::cout << sr.first.first << " with rule: " << sr.first.second << " and value " << std::get<0>(sr.second) << std::endl;

// Output:
// 687 with rule: 000001F9B60509E0 and value 1
// 688 with rule: 000001F9B60506E0 and value 2

const auto pp3 = ruleSavedData(687.00, test3);
_splitRulePool[pp3] = std::tuple<int, int, int>({ 3, 0, 0 });

for (const auto& sr : _splitRulePool)
    std::cout << sr.first.first << " with rule: " << sr.first.second << " and value " << std::get<0>(sr.second) << std::endl;

// Output:
// 687 with rule: 000001F9B60509E0 and value 3              -> key of pp1 gets overwritten with sortByDouble choice 1 but not with the others
// 688 with rule: 000001F9B60506E0 and value 2

// "Expected" output:
// 687 with rule: 000001F9B60509E0 and value 1
// 687 with rule: (&pp3) and value 3                       // comes after simply because first sort < key is not true
// 688 with rule: 000001F9B60506E0 and value 2



delete test1;
delete test2;
delete test3;


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source