【问题标题】:Why will std::sort crash if the comparison function is not as operator <?如果比较函数不是运算符 <,为什么 std::sort 会崩溃?
【发布时间】:2021-11-19 13:42:45
【问题描述】:

以下程序是用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 &lt;= other.a; 更改为return a &lt; other.a;,那么程序将按预期运行,没有任何异常。

为什么?

【问题讨论】:

  • std::sort 的比较器需要严格的弱排序,&lt;=提供。
  • 你应该为 A ctor 写 a(0)...但它不会在这里崩溃!
  • @LaszloPapp:是的。它对a() 进行值初始化(这就是a() 的含义),对于int 而言,这意味着0。
  • 请将未定义行为 &coll[8] 替换为 coll + 8

标签: c++ algorithm exception standards


【解决方案1】:

std::sort 需要一个满足 严格弱排序 规则的排序器,对此进行了解释 here

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

【讨论】:

  • +1 这很好地说明了std::sort 的比较器的要求。如果您的编译器与 C++11 兼容(并且 OP is 兼容;VS2012),我将使用 std::sort(std::begin(coll), std::end(coll)); 来遵循这一点。如果您曾经更改数组的尺寸,或者改用任何标准容器,您会很高兴的。
  • 进入无限循环只会导致它卡住。相反,它转储核心。为什么?
  • @btilly 我认为是因为std::sort 使用递归算法,在无限循环的情况下会导致堆栈溢出。
  • 您必须详细了解它检查的内容,但标准的排序例程旨在运行得非常非常快,因此它们不会检查您所做的一切以查看是否正常,他们只是依靠它。如果你的比较返回了不可能的结果,那么不可能的事情就会发生——比如说它得到了一些比较的结果,并且它使用它作为查找位置的索引,只有它“知道”哪些值是可能的并且“知道”结果引用将在有效存储中,因此它只是获取它。 Kaboom:SIGSEGV 运气好。如果运气不好,它会默默地处理您的数据。
【解决方案2】:

xorguy 的答案还不错。

我只想从标准中添加一些引用:

25.4 排序及相关操作[alg.sorting]

为了使 25.4.3 中描述的算法以外的算法正常工作,comp 必须对值引入 严格的弱排序

术语 strict 指的是非自反关系的要求(!comp(x, x) 对于所有 x),术语 weak 指的是非自反关系的要求与全排序一样强,但比部分排序强。

所以 xorguy 解释得很好:你 comp 函数说 a &lt; ba == b 不遵循 严格弱排序 规则...

【讨论】:

    【解决方案3】:

    您的代码的问题是您正在访问无效的内存。代码

    coll[8]
    

    试图访问最后一个数组元素之后的元素(最后一个元素索引为 7)。 我建议使用 std::array 代替纯 C 数组。

    std::array<A, 8> a;
    
    // fill it somehow
    
    std::sort(a.begin(), a.end());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-23
      • 2022-10-24
      • 2013-01-13
      • 2019-10-23
      • 1970-01-01
      相关资源
      最近更新 更多