为什么如果比较函数不是运算符<,std::sort 会崩溃?

Why will std::sort crash if the comparison function is not as operator <?

提问人:xmllmx 提问时间:8/18/2013 更新时间:2/21/2020 访问量:16203

问:

以下程序是使用 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;

为什么?

C++ 算法 异常 标准

评论

8赞 WhozCraig 8/18/2013
比较器需要严格的弱排序,这提供。std::sort<=
0赞 László Papp 8/18/2013
你应该为 A ctor 写 a(0) ...但无论如何它都不会在这里崩溃!
3赞 GManNickG 8/18/2013
@LaszloPapp:是的。它值初始化(这就是意思),这意味着 0。a()a()int
1赞 GManNickG 8/18/2013
@LaszloPapp: stackoverflow.com/questions/14259602/...
1赞 8/18/2013
请将未定义的行为 &coll[8] 替换为 coll + 8

答:

41赞 xorguy 8/18/2013 #1

std::sort需要满足严格的弱排序规则的分拣机,此处对此进行了说明

因此,你的比较器说,当它不遵循严格的弱排序规则时,算法可能会崩溃,因为它会进入无限循环。a < ba == b

评论

6赞 WhozCraig 8/18/2013
+1 这很好地说明了比较器的要求。如果您的编译器符合 C++11(并且 OP 符合;VS2012)。如果您更改了数组的尺寸,或者改用任何标准容器,您会很高兴自己这样做了。std::sortstd::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 解释得很好:你的函数说,当它不遵循严格的弱排序规则时......compa < ba == 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());