I'm learning std::set . Here is my codes:
#include <set>
#include <iostream>
using namespace std;
struct cmp{
bool operator () (const int & a,const int & b) const {
if(abs(a-b)<=3)
return false;
return a < b;
}
};
set<int,cmp> q{1, 2, 10};
int main(){
if(q.find(4)!=q.end())
cout << 1;
else
cout << 2;
}
Output: 1
I use struct cmp to custom elements's sort rules,if abs(a-b)<=3 the new element will be delete.
But what surprised me was that q.find() had been changed.
I want to know why the output is 1,there is no 4 in q.
q.find(4) is to get a iterator where the element equals 4 in q , isn't it?
CodePudding user response:
You seem to expect that the set
uses your comparator to check if two elements are equal (edit: on a second read, actually no, you are not checking for equality, but that does not change much on the answer). Thats not the case. A set
does not care about equality. Two elements are considered equivalent when
!(cmp(a,b) && !(cmp(b,a)
Consider the simple case of integers and cmp == std::less
then this is just
!(a < b) && !( b < a)
And with integers this can only be true
when a == b
. However, in general equivalence is not equality. In any case it is not cmp
that should return true
when two elements can be considered equivalent. cmp(a,b)
should be true
when a
comes before b
when the two are sorted.
This only works consistently when cmp
implements a strict weak ordering as you can read here: https://en.cppreference.com/w/cpp/named_req/Compare
Your code has undefined behavior, because your comparator does not meet that requirement. It does not implement a strict weak ordering.
There is also no obvious way to fix that, because your way of comparing two elements cannot be used to sort them. Consider the following:
// 1 and 3 are equivalent because
!cmp(1,3) && !cmp(3,1) == !false && !false == true
// 3 and 5 are equivalent because
!cmp(3,5) && !cmp(5,3) == !false && !false == true
but
// 1 and 5 are not equivalent because
!(cmp(1,5) && !cmp(5,1) == !true && !false == false
This is not consistent. Sloppy speaking, if two elements are equivalent it does not matter how you arrange them when sorting. It does not matter how 1 and 3 are arranged with respect to each other you can swap them with out breaking the ordering. Same holds for 3 and 5. But the order matters for 1 and 5. That is not consistent. Formally, it breaks the last requirement of a strict weak ordering as explained in the link above, as has been pointed out by Sebastian Redl in a comment.