C++ sort用<=比较器报错原因及比较器底层工作原理
以下代码运行时会触发异常直接终止,报错信息如下:
terminate called after throwing an instance of 'std::length_error'
what(): basic_string::_M_create
当把比较函数comp中的判断条件修改为s1.size() < s2.size()时,程序可以正常运行并输出正确结果。
存在问题的完整代码如下:
static bool comp(const string& s1,const string& s2){ return s1.size()<=s2.size(); } int main() { int n; cin>>n; vector<string> words(n); for(int i=0;i<n;++i){ cin>>words[i]; } sort(words.begin(),words.end(),comp); for(int i=0;i<n;++i){ cout<<words[i]<<" "; } return 0; }
C++ 标准库所有依赖自定义比较器的排序类算法(最典型的就是std::sort),都强制要求传入的比较函数满足严格弱序规则——这是排序算法内部状态判断、位置调整、区间收敛逻辑能正确运行的核心前提,核心约束包含四点:
- 反自反性:对任意元素
a,comp(a,a)必须返回false,即一个元素不能被判定为需要排在自身前面 - 不对称性:对任意两个元素
a、b,如果comp(a,b)返回true,则comp(b,a)必须返回false,不能同时出现a应排在b前、b应排在a前的矛盾结果 - 传递性:如果
comp(a,b)为true且comp(b,c)为true,则comp(a,c)必须为true - 等价传递:如果
a和b等价(即comp(a,b)和comp(b,a)都返回false),b和c等价,则a和c也必须判定为等价
std::sort内部是快速排序、插入排序、堆排序结合的混合实现,排序全程会基于上述规则做边界计算和元素交换,一旦比较器不满足规则,内部逻辑会直接进入不可预期的状态,触发C++标准中定义的未定义行为。
示例中使用的比较器return s1.size() <= s2.size()直接违反了严格弱序的核心约束:当两个字符串长度相等时,comp(s1,s2)会返回true,反过来comp(s2,s1)也会返回true,既不满足反自反性(元素与自身比较返回true),也不满足不对称性,直接导致排序内部的边界计算、位置调整逻辑错乱。
你看到的basic_string::_M_create报错并不是问题的根源,只是未定义行为最终触发崩溃的落点:排序逻辑错乱后,可能出现越界访问容器内存、迭代器指向非法地址、计算出异常的字符串长度值等问题,最终当string类尝试申请内存创建对象时,检测到传入的长度参数是非法值,就会抛出length_error异常终止程序。
当判断条件改为s1.size() < s2.size()时,长度相等的字符串双向比较都会返回false,会被判定为等价元素,完全符合严格弱序的所有要求,排序逻辑可以正常收敛执行,因此不会触发错误。
内容的提问来源于stack exchange,提问作者suthar0

