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.