c++ – Problem overloading less to Set container

Question:

Hello, I would like to know why in the "cjnt2" set, when printing it seems that it is saving the element {"alias2", 2} when, according to the operator that I have overloaded, it should remove it from the cjnt2 Set. Thanks

#include <iostream>
#include <string>
#include <set>
using namespace std;
struct contestant {
    string name;
    int money;
    bool operator<(const contestant &other) const {
        return name != other.name && money >= other.money;
    }
};

int main() {

  set<contestant> cjnt2;

 cjnt2 = { 
     {"alias9", 10},
    {"alias2", 11},
    {"alias2", 2},
    {"alias3", 20},
    {"alias8", 10},
    {"alias1", 10} 
  };

    for (auto a: cjnt2)
    cout << a.name<< " "<< a.money << endl;

}

Answer:

It adds both elements to you because the function does not do what is expected of it.

According to the set documentation:

two objects a and b are considered equivalent if neither compares less than the other:! comp (a, b) &&! comp (b, a)

That is, two objects will be considered equivalent if a<b == false and b<a == false .

That in theory checks out well … but the order of element comparison is equally important …

Let's tweak the function a bit to see what happens:

bool operator<(const contestant &other) const
{
    std::cout << "(" << name << " " << money << ") vs (" << other.name << " " << other.money << ") = " << (name != other.name && money >= other.money? "TRUE" : "FALSE") << '\n';
    return name != other.name && money >= other.money;
}

If we run the code, we see that the set is generating the following comparisons:

(alias9 10) vs (alias2 11) = FALSE
(alias2 11) vs (alias9 10) = TRUE
(alias2 11) vs (alias9 10) = TRUE
(alias9 10) vs (alias2 2) = TRUE
(alias2 2) vs (alias9 10) = FALSE
(alias2 2) vs (alias3 20) = FALSE
(alias3 20) vs (alias9 10) = TRUE
(alias3 20) vs (alias2 11) = TRUE
(alias3 20) vs (alias2 11) = TRUE
(alias2 2) vs (alias8 10) = FALSE
(alias8 10) vs (alias9 10) = TRUE
(alias8 10) vs (alias2 11) = FALSE
(alias2 11) vs (alias8 10) = TRUE
(alias8 10) vs (alias2 11) = FALSE
(alias2 2) vs (alias1 10) = FALSE
(alias1 10) vs (alias9 10) = TRUE
(alias1 10) vs (alias2 11) = FALSE
(alias1 10) vs (alias8 10) = TRUE
(alias2 11) vs (alias1 10) = TRUE
(alias1 10) vs (alias8 10) = TRUE

If we focus on the ones that interest us:

(alias9 10) vs (alias2 2) = TRUE
(alias2 2) vs (alias9 10) = FALSE
(alias2 2) vs (alias3 20) = FALSE

We see that at no time has (alias2 2) been compared with (alias2 11) . It has simply come out that (alias2 2) is less than (alias3 20) and there it has stopped comparing … the object you want to delete has already found its place in the set !!!

And why hasn't it come to compare with (alias2 11) ?

Precisely because the value of money causes changes in the comparisons:

(alias2 11) vs (alias9 10) = TRUE
(alias2 2) vs (alias9 10) = FALSE

Since this first comparison is different, in the list of elements against which it is checked (alias2 2) will never be (alias2 11) :

 (alias2 11) < (alias9 10) < (alias2 2)

Well, just tweak the function slightly for everything to work:

bool operator<(const contestant &other) const
{
    return name < other.name;
}

We have removed the variable money from the comparison since if we do not allow duplicate names, the value of money is irrelevant.

Scroll to Top