问题: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. 【51NOD-0】1011 最大公约数GCD

    [算法]欧几里德算法 #include<cstdio> int gcd(int a,int b) {?a:gcd(b,a%b);} int main() { int a,b; scanf( ...

  2. 【游记】CTSC&APIO2017

    GDOI回来不到两天就前往北京参加CTSC和APIO. CTSC Day1 [考试] T1一道神奇的题,很快想到O(n2)做法,感觉ctsc题目难度应该很大,就没马上想着出正解(事实上这届CTSC偏水 ...

  3. TOJ 1049 Jesse's problem (最短路 floyd)

    描述 All one knows Jesse live in the city , but he must come to Xiasha twice in a week. The road is to ...

  4. bzoj 1588 bst

    用set存下就好了. /************************************************************** Problem: 1588 User: BLADE ...

  5. python调参神器hyperopt

    一.安装 pip install hyperopt 二.说明 Hyperopt提供了一个优化接口,这个接口接受一个评估函数和参数空间,能计算出参数空间内的一个点的损失函数值.用户还要指定空间内参数的分 ...

  6. 概率DP入门学习QAQ

    emmmm博客很多都烂尾了...但是没空写..先写一下正在学的东西好了 概率DP这东西每次考到都不会..听题解也是一脸懵逼..所以决定学习一下这个东东..毕竟NOIP考过...比什么平衡树实在多了QA ...

  7. fork与vfork区别

    1. 地址空间各段拷贝: fork: 内核为子进程生成新的地址空间结构,拷贝父进程的代码段,数据空间,堆,栈到自身的地址空间,但注意:子进程的代码段并不会分配物理空间,而是指向父进程的代码段物理空间, ...

  8. jstorm相关

    https://www.cnblogs.com/antispam/p/4182210.html

  9. freemark基础知识

    前言:使用freemarker对应生成一个html文件,保存到磁盘,访问文件就不一定使用tomcat,可以使用nginx(http服务器)访问.可以使用freemaker工具生成.只生成一次,html ...

  10. memcache和redis的对比

    1.memcache a.Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站 ...