问题:sort的比较函数实现有问题导致进程调用sort时core了。
结论:特别要注意,sort的比较函数必须遵循严格弱排序(strict weak ordering)的规则。
 
这是最近在工作中遇到的一个问题,平时用函数就简单看了函数原型和例子,如无需要,没有去细究太多。结果在sort的使用就碰钉子,今天分享出来,大家也给自己提个醒。不多赘述,直接贴代码。
 
1. std::sort的调用
 
2. 比较函数compareFriUser
 
编译是没问题的,但是运行到这里就会导致core。core的堆栈如下:
 
 
第一次见到这样的core文件,当时第一感觉是怀疑<algorithm>提供的sort的排序算法是不是有问题,当然这么怀疑一个经过历史洗礼的标准库是很蠢的事情。
后面在网上找到了问题所在。
我们所使用的sort原型是这样:
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

手册中对于第三个参数的说明是这样(http://www.cplusplus.com/reference/algorithm/sort/?kw=sort ):

comp
Binary function that accepts two elements in the range as arguments, and returns a value convertible tobool. The value returned indicates whether the element passed as first argument is considered to go before the second in the specific strict weak ordering it defines.
The function shall not modify any of its arguments.
This can either be a function pointer or a function object.
(翻译:comp是一个接受两个表示范围的元素作为参数的二元函数,它返回一个可转成bool的值。返回值指示了在comp定义的特定的严格弱排序中,第一个参数是否应该排在第二个参数之前。comp函数不会改变任何一个参数,它可以是一个函数指针或一个仿函数。)
 
我们注意到该说明提到了comp参数必须是严格弱排序。网上的一个较好的解读是:严格是说在判断的时候会用"<",而不是"<=",弱排序是因为,一旦"<"成立便认为存在"<"关系,返回ture,而忽略了"="关系和">"区别,把它们归结为false。相关定义可以参阅:http://www.sgi.com/tech/stl/StrictWeakOrdering.html
简单说,在comp中,当参数1和参数2等价时,必须返回false.
在截图中的compareFriUser中,CSGameUser的等价条件是online、hasMsg、m_vip_level都相等,参数1既不小于参数2,参数2也不小于参数1,此时两者等价。
而在中,当p1->m_vip_level == p2->m_vip_level ,却返回了1. 这就违反了严格弱序的定义,会导致不可预估的结果。
在这里,我们只要把这句代码改成p1->m_vip_level > p2->m_vip_level ,问题就解决了。
 
而这样的比较函数之所以会导致sort内部调用core是因为sort内部的排序函数不会进行边界检查,而p1->m_vip_level == p2->m_vip_level 时return true会导致其取到不正确的元素地址。关于这个问题,可参考该链接:http://verihy.me/posts/stdsort-cmp-order/
(该问题可以去仔细研读sort的具体实现)
 
关于以上的问题,在《Effective STL》的条款20和21都有提到,《STL源码剖析》关于sort函数源码也有详细的解读。大家可以去阅读一下。尤其是STL中有很多很好用的函数和数据结构,在没有仔细阅读使用手册的情况下,按照自己的理解去使用它们有时会导致出现不可预估的结果,这个时候参阅这两本书籍和说明文档是十分有用的。

调用sort段错误问题的更多相关文章

  1. libvlc_new 调用产生段错误

    在调试程序的时候,碰到一个奇怪的段错误问题.只要链接的时候使用-Wl,-rpath=./vlc/lib就会产生段错误,如果链接的时候使用的是-Wl,-rpath=../../tool/vlc/lib则 ...

  2. linux C++ 莫名奇异的段错误(segmentation fault),无法调用其他函数

    进来在linux下开发C++项目,遇到了非常奇怪的bug. 项目须要多线程实现,在写好代码后,每当执行到线程函数内部,当内部调用其他函数如printf.fopen等时就会提示段错误(segmentat ...

  3. 【转】段错误调试神器 - Core Dump详解

    from:http://www.embeddedlinux.org.cn/html/jishuzixun/201307/08-2594.html 段错误调试神器 - Core Dump详解 来源:互联 ...

  4. linux下cp覆盖原so文件时引起的段错误原因确定

    原创作品,转载请注明出处http://www.cnblogs.com/leo0000/p/5694416.html 最近因为一个很有意思的段错误学习了一些新的东西. 当时现象是这样的,程序正在运行,系 ...

  5. Linux环境下段错误的产生原因及调试方法小结(转)

    最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且 项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation F ...

  6. Linux环境下段错误的产生原因及调试方法小结

    转载自http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之 ...

  7. 【转】gdb 调试段错误

    [转]gdb 调试段错误 转自:blog.csdn.net/yangzhu1982/article/details/6318600 开发嵌入式Linux的时候经常会遇到segmentation fau ...

  8. Linux下的段错误(Segmentation fault)

    Linux开发中常见段错误问题原因分析 1 使用非法的内存地址(指针),包括使用未经初始化及已经释放的指针.不存在的地址.受系统保护的地址,只读的地址等,这一类也是最常见和最好解决的段错误问题,使用G ...

  9. strcat函数造成的段错误(Segmentation fault)

    转自:http://book.51cto.com/art/201311/419441.htm 3.21  strcat函数造成的段错误 代码示例 int main() { char dest[7]=& ...

随机推荐

  1. 【BZOJ】3779 重组病毒

    [算法]Link-Cut Tree+线段树(维护DFS序) [题解]整整三天……T_T 这篇题解比较资瓷:permui 这道题虽然树形态没有变化,但用lct写的原因在于把题目中的操作一进行了神转化:每 ...

  2. vue-awesome-swipe 基于vue使用的轮播组件 使用(改)

    npm install vue-awesome-swiper --save  //基于vue使用的轮播组件 <template> <swiper :options="swi ...

  3. javascript语言中的一等公民-函数

    简介 在很多传统语言(C/C++/Java/C#等)中,函数都是作为一个二等公民存在,你只能用语言的关键字声明一个函数然后调用它,如果需要把函数作为参数传给另一个函数,或是赋值给一个本地变量,又或是作 ...

  4. C++之参数总结

    函数的形参为函数提供了已命名的局部存储空间,它是在函数的形参表中定义的,并由调用函数时传递给函数的实参初始化,而形参的 初始化与变量的初始化一样,如果形参具有非引用类型,则复制实参的值,如果形参为引用 ...

  5. python内建方法

    abs all any apply basestring bin bool buffer bytearray bytes callable chr classmethod cmp coerce com ...

  6. 关于JqueryEasyUI插件—Tab,默认选中某个面板 如果不明显指定的话,第一个就是被选中的

    如果不明显指定的话,第一个就是被选中的,你可以通过data-options="selected:true"指定默认选中

  7. IE11中实现颜色渐变

    background: -ms-linear-gradient(left,#daa23e,#ad7f27); 下面是css3中颜色渐变对各个浏览器的写法:background: -webkit-lin ...

  8. javascript 实现图片拖动

    javascript实现图片拖动效果并不难,主要的思路如下 1:给图片绑定监听鼠标按下对象,设置拖动属性为true 2:鼠标抬起:拖动属性为false 鼠标移动:改变坐标即可,新坐标=图片原始坐标+鼠 ...

  9. POJ-2563

    Pick-up sticks Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 10364   Accepted: 3842 D ...

  10. php文件上传错误信息

    错误信息说明 UPLOAD_ERR_OK:其值为0,没有错误发生,文件上传成功 UPLOAD_ERR_INI_SIZE:其值为1,上传的文件超过了php.ini和upload_max_filesize ...