问题: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. 【vijos】P1448 校门外的树

    [题意]两种操作,[L,R]种新的树(不覆盖原来的),或查询[L,R]树的种类数.n<=50000. [算法]树状数组||线段树 [题解]这题可以用主席树实现……不过因为不覆盖原来的,所以有更简 ...

  2. 【BZOJ】1607: [Usaco2008 Dec]Patting Heads 轻拍牛头

    [算法]模拟 #include<cstdio> #include<algorithm> using namespace std; ,maxm=; int a[maxn],A[m ...

  3. 【51NOD-0】1106 质数检测

    [算法]数学 #include<cstdio> #include<cmath> bool ok(int x) { int m=(int)sqrt(x+0.5); ;i<= ...

  4. Python 用ctypes观察Python对象的内存结构 -- (转)

    !!!强烈推荐的好文章!!! 对象的两个基本属性 Python所有对象结构体中的头两个字段都是相同的: refcnt:对象的引用次数,若引用次数为0则表示此对象可以被垃圾回收了. typeid:指向描 ...

  5. hdu 1253 胜利大逃亡(简单题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1253 题目大意:在所给的时间能顺利离开城堡. #include <iostream> #i ...

  6. 结合BeautyEye开源UI框架实现的较美观的Java桌面程序

    BeautyJavaSwingRobot 结合BeautyEye开源UI框架实现的较美观的Java桌面程序,主要功能就是图灵机器人和一个2345网站万年历的抓取.... 挺简单而且实用的一个项目,实现 ...

  7. $(document).ready 和 window.onload 的区别

    1.相同点 两者都用于在网页加载完后执行相应代码块. 2.不同点 window.onload 在创建完 DOM 树后,所有外部资源(图片.Flash 动画等)加载完成,且整个页面在浏览器窗口中显示完毕 ...

  8. centos 快捷键

    centos 快捷键大全 时间:2013-02-23 14:54来源:blog.csdn.net 举报 点击:225次 新手通常会不太习惯GNOME或KDE的界面操作,不过还好,LINUX的快捷键大多 ...

  9. 集合类---Map

    Map常用的子类: 一.HashMap详解  1.特点 1)线程不安全.如果想要得到线程安全的HashMap,可以使用Collections的静态方法:Map map = Collections.sy ...

  10. Deep Learning基础--参数优化方法

    1. 深度学习流程简介 1)一次性设置(One time setup)          -激活函数(Activation functions) - 数据预处理(Data Preprocessing) ...