标准排序有时会引发分段错误

Posted

技术标签:

【中文标题】标准排序有时会引发分段错误【英文标题】:std sort sometimes throws seqmention fault 【发布时间】:2021-05-16 04:00:20 【问题描述】:

我编写了以下函数,用于对数组向量进行部分稳定排序。当向量的大小像 1G 一样小时它总是可以工作,当向量的大小很大(5 或 6 Gig)时它有时会工作,有时它会抛出分段错误,有人可以帮我弄清楚这个问题。

template <typename T, size_t SIZE>
void sort(std::vector<std::array<T, SIZE>>& vec, size_t depth = SIZE) 
        std::sort(vec.begin(), vec.end(),
                  [&](const auto& t1, const auto& t2)->bool 
                        for(size_t s = 0; s < depth; s++) 
                                if(t1[s] == t2[s]) 
                                        continue;
                                
                                return t1[s] < t2[s];
                        
                        return true;
                  );

我使用 g++ 10.2,这些是开关,我用 -DNDEBUG -march=native -msse3 -ftree-vectorize -O3 编译代码。

【问题讨论】:

您的比较函数在t1==t2 时返回true,它可能不应该那样做。 【参考方案1】:

std::sort 要求比较函数是"strict weak ordering",这要求:

它是不自反的:对于所有xr(x, x) 都是假的;

你的比较函数不满足这个要求,因为as Mark Ransom pointed out in the comments,你在t1 == t2时返回true。你的比较基本上是&lt;=而不是&lt;,你需要是&lt;

最简单的解决方法是使用std::lexicographical_compare

template <typename T, size_t SIZE>
void sort(std::vector<std::array<T, SIZE>>& vec, size_t depth = SIZE) 
        std::sort(vec.begin(), vec.end(),
                  [depth](const auto& t1, const auto& t2)->bool 
                        return std::lexicographical_compare(t1.begin(), t1.begin() + depth,
                                                            t2.begin(), t2.begin() + depth);
                  );

为了完整起见,请注意,如果您不关心 depth,可以直接排序,因为 std::array 带有内置的 operator&lt;,可以按字典顺序进行比较。

【讨论】:

这是一个很好的观察。你知道为什么存在这个要求吗? @MarkRansom 我没有想到,但this answer 似乎有一个很好的解释 @MarkRansom,我认为这是因为否则sort 将需要两个单独的函数来排序,“小于”(像往常一样)以及相等。 @alfC 通常不需要在排序中测试相等性。一个天真的期望是测试 &lt;= 而不是 &lt; 只会导致具有相同键的项目的不确定排序,而不是完全崩溃。 @MarkRansom。同意,这就是重点,解释一下:如果排序是严格,通常不需要在排序中测试相等性。

以上是关于标准排序有时会引发分段错误的主要内容,如果未能解决你的问题,请参考以下文章

分段错误:在 C++ 中弹出向量时出现 11

为啥 C++ 标准向量在分配或调整大小时会出现段错误? [关闭]

qapps 运行良好但断点有时会产生分段错误

C快速排序(链表)分段错误

localtime() - 分段错误

OpenCV 分配导致 std::thread::join 中的段错误