对于下面的这段代码:
int main()
{
std::set<Node> s;
for (int i = 0; i <= 5; i++)
s.insert(Node(i));
s.insert(Node(4));
for (auto itor = s.begin(); itor != s.end(); itor++)
{
std::cout << itor->val << ' ';
}
}
当符号"<"被覆盖时,如下所示,输出为:"5 4 3 2 1 0">
struct Node
{
int val;
Node(int _val = -1) : val(_val) {}
bool operator<(const Node &p) const
{
return val > p.val;
}
};
当我将函数更改为以下内容时:
bool operator<(const Node &p) const
{
return val >= p.val;
}
输出变为:"5 4 4 3 2 1 0"。 这种差异让我感到困惑,有人可以解释为什么会发生这种情况并解释"插入"功能的原理吗?
std::set
默认对键类型使用operator<
,因此在第一种情况下,它使用为Node
定义的operator<
来比较键,而又使用>
来比较基础整数,因此您会看到整数的降序序列。
std::set
期望提供的订单是作为先决条件的严格弱订单。 在第二种情况下,你的operator<
不是一个严格的弱订单,因此你违反了前提条件,触发了未定义的行为。 因此,实现是混乱的。 (未定义的行为意味着任何事情都可能发生——程序可能会产生奇怪的结果、崩溃、让您的计算机着火、产生鼻魔等。
STL 容器中的自定义比较函数必须满足要求,即它们必须诱导出严格的弱排序关系。第二个运算符重载val >= p.val
无法做到这一点,因此行为是未定义的。
从 cpp首选项 在 std::set 上:
在标准库使用比较要求的所有地方,唯一性都是通过使用等价关系来确定的。在不精确的术语中,如果两个对象 a 和 b 的比较都不比另一个少,则被认为是等价的:
!comp(a, b) && !comp(b, a)
。