对于下面的这段代码?
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 << ' ';
}
}
Run Code Online (Sandbox Code Playgroud)
当符号'<'如下重写时,输出为:'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;
}
};
Run Code Online (Sandbox Code Playgroud)
当我将函数更改为此:
bool operator<(const Node &p) const
{
return val >= p.val;
}
Run Code Online (Sandbox Code Playgroud)
输出变为:'5 4 4 3 2 1 0'。这种差异使我感到困惑,有人可以解释为什么会发生这种情况并解释“插入”功能的原理吗?
std::set
operator<
默认情况下在键类型上使用,因此在第一种情况下,它使用operator<
defined用于Node
比较键,而键又用于>
比较基础整数,因此您看到了一个由整数组成的降序序列。
std::set
希望提供的订单是严格的弱订单作为前提。在第二种情况下,您operator<
不是严格的弱命令,因此您违反了前提条件,从而触发了未定义的行为。因此,实现是混乱的。(未定义的行为表示可能发生任何事情,该程序可能会产生奇怪的结果,崩溃,使计算机着火,产生鼻恶魔等)
STL容器中的自定义比较功能必须满足要求,即它们必须引起严格的弱排序关系。使用的第二个运算符重载val >= p.val
无法完全做到这一点,因此行为未定义。
从std :: set上的cppreference:
标准库在所有使用比较要求的地方,唯一性都是通过等价关系确定的。用不精确的术语来说,如果两个对象a和b的比较值都不小于另一个,则视为等效
!comp(a, b) && !comp(b, a)
。