对空向量进行 std::sort [关闭]

Posted

技术标签:

【中文标题】对空向量进行 std::sort [关闭]【英文标题】:std::sort on empty vector [closed] 【发布时间】:2014-06-18 16:28:21 【问题描述】:

如果std::sort 得到一个空范围,它是否应该正常工作?

我收到此代码的分段错误 (gcc 4.8.3):

std::vector<float> f;
std::sort( f.begin() + 1, f.end() );

标准规定对于空向量 begin()end() 返回相同的值。所以我希望sort 在上述情况下什么都不做,因为它应该得到一个空范围:begin()+1 应该大于end()

这个空范围排序没有问题:

std::sort( f.begin(), f.end() );

【问题讨论】:

那么f.begin() + 1 呢?那岂不是越界了? @juanchopanza 这是一些价值,重要的是begin() + 1 是> end() 这是一个无效迭代器的值。它不是&gt;&lt; 而不是end()。它只是无效的。 @user2052436,这是未定义的行为。在一个空范围内,begin() == end() 【参考方案1】:

std::sort 期望[begin, end) 是一个有效范围,这样如果你不断增加begin,你最终会到达end。在您的情况下,begin()+1 超出了end(),因此std::sort 无法知道它正在查看范围的末尾。

std::sort 接受迭代器,而不是指针。正因为如此,它无法运行begin &lt; end 检查:如果您为两个迭代器传递了rbegin()rend(),这将失败。

如果您想对不包括初始元素的std::vector 的一部分进行排序,则需要确保容器不为空。否则,begin()+1 将产生无效的迭代器。

注意:虽然从技术上讲,当您在空容器上执行 begin()+1 时会发生未定义的行为,但您的情况下的崩溃几乎肯定来自 std::sort 内部的取消引用。另请注意,如果您有兼容 C++11 的编译器,则使用 std::next(v.begin(), 1) 比使用 v.begin() + 1 更可取。

【讨论】:

你没有进入 std::sort,一切都已经结束了。 好的,现在你也指出实际的错误,我推翻了我的投票。【参考方案2】:

输入迭代器的增量有一个先决条件,即迭代器必须是可解引用。对于空向量,v.begin() 是不可取消引用的,因此尝试执行 v.begin() + 1(它又以增量定义)是未定义的行为。

此外,std::sort(begin, end) 要求 [begin, end) 是一个有效范围,标准规定 (§24.2.1 [iterator.requirements.general]/p7)

当且仅当j 可以从i 到达时,范围[i,j) 才有效。将库中的函数应用于无效范围的结果未定义。

对于大多数随机访问迭代器(唯一定义了&lt;&gt; 的迭代器类型),如果a &gt; ba 无法从b 访问,因此[a, b) 确实not 表示空范围 - 它根本不表示有效范围。

【讨论】:

@Deduplicator ...这是第一段? @Deduplicator UB 并不总是直接显示。在这里,段错误可能源自it != end,因此取消引用begin + 1(指向无效内存,是的)将会发生,所以繁荣。是的,从技术上讲,该程序在v.begin() + 1 展示了 UB,但其余部分也很重要。 @Deduplicator v.begin() + 1 是未定义行为的原因恰恰是因为v.begin() 是不可取消引用的,并且您违反了先决条件。【参考方案3】:

f.begin()+1 超出范围,这就是分段错误的原因。

使用f.begin() 作为数组的开头。这样可以安全使用。

【讨论】:

好的,所以要排除第一个元素,我需要在调用sort之前检查size() &gt; 0

以上是关于对空向量进行 std::sort [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

std :: sort不会移动向量的元素[关闭]

使用 std::sort 对对象向量进行排序

使用 std::sort 对具有特定标准的二维向量进行排序

如何使用 std::sort() 对指向值的向量进行排序?

C++ - 使用 std::sort 对结构向量进行排序导致读取访问冲突

使用 std::sort() 对对象向量进行排序