提问人:xmllmx 提问时间:8/18/2013 更新时间:2/21/2020 访问量:16203
为什么如果比较函数不是运算符<,std::sort 会崩溃?
Why will std::sort crash if the comparison function is not as operator <?
问:
以下程序是使用 VC++ 2012 编译的。
#include <algorithm>
struct A
{
A()
: a()
{}
bool operator <(const A& other) const
{
return a <= other.a;
}
int a;
};
int main()
{
A coll[8];
std::sort(&coll[0], &coll[8]); // Crash!!!
}
如果我更改为,那么程序将按预期运行,无一例外。return a <= other.a;
return a < other.a;
为什么?
答:
41赞
xorguy
8/18/2013
#1
std::sort
需要满足严格的弱排序规则的分拣机,此处对此进行了说明
因此,你的比较器说,当它不遵循严格的弱排序规则时,算法可能会崩溃,因为它会进入无限循环。a < b
a == b
评论
6赞
WhozCraig
8/18/2013
+1 这很好地说明了比较器的要求。如果您的编译器符合 C++11(并且 OP 符合;VS2012)。如果您更改了数组的尺寸,或者改用任何标准容器,您会很高兴自己这样做了。std::sort
std::sort(std::begin(coll), std::end(coll));
0赞
btilly
8/18/2013
进入无限循环应该只会导致它被卡住。相反,它会转储核心。为什么?
3赞
xorguy
8/18/2013
@btilly我认为是因为使用了递归算法,在无限循环的情况下会导致堆栈溢出。std::sort
1赞
jthill
8/18/2013
你必须深入了解它检查的内容,但标准的排序例程旨在运行得非常非常快,所以它们不会检查你所做的一切,看看它是否正常,他们只是依赖它。如果你的比较返回了不可能的结果,那么不可能的事情就会发生——比如说它得到了一些比较的结果,它用它作为在哪里查看的索引,只有它“知道”哪些值是可能的,并且“知道”生成的引用将在有效的存储中,所以它只是获取它。Kaboom:SIGSEGV 运气好。运气不好的话,它会悄悄地冲洗你的数据。
10赞
Pierre Fourgeaud
8/18/2013
#2
xorguy 的答案非常好。
我只想从标准中添加一些引述:
25.4 排序和相关操作 [alg.sorting]
要使 25.4.3 中描述的算法以外的算法正常工作,comp 必须对值进行严格的弱排序。
术语“严格”是指对非反身关系的要求(对所有 x 的 !comp(x, x)),而“弱”项是指不如总排序的要求强,但比部分排序的要求强的要求。
所以 xorguy 解释得很好:你的函数说,当它不遵循严格的弱排序规则时......comp
a < b
a == b
-1赞
Khabarov Boris
2/21/2020
#3
代码的问题在于您访问了无效的内存。法典
coll[8]
尝试访问最后一个数组元素之后的元素(最后一个元素索引为 7)。 我建议使用 std::array 而不是普通的 C 数组。
std::array<A, 8> a;
// fill it somehow
std::sort(a.begin(), a.end());
评论
std::sort
<=
a()
a()
int