C++ map自定义比较函数遵守严格弱序

问题背景及定位

背景:这个问题是在将tablesaw(一个Java的数据处理项目)迁移到C++时出现的。

问题位置:SplitOn()函数,在数据流水线中的aggregate阶段。

问题描述:使用google/benchmark进行了批量化的性能测试,在测试中出现偶发性段错误,几率大约在万分之一到十万分之一之间。

问题定位:由于开发环境为受限环境,无法使用GDB调试查看堆栈定位,只能使用打印日志的方式处理

定位问题出现在如下代码处:

  1. struct ByteArrayCompare {
  2. bool operator()(const ByteArray &a, const ByteArray &b) const {
  3. for (int i = 0; i < min(a.byteArray.size(), b.byteArray.size()); i++)
  4. {
  5. if (a.byteArray[i] != b.byteArray[i])
  6. return a.byteArray[i] < b.byteArray[i];
  7. }
  8. return true;
  9. }
  10. typedef ByteArray value_type;
  11. };
  12. ......
  13. map<ByteArray, Selection, ByteArrayCompare> selectionMap;
  14. ......
  15. selectionMap[instanceByteArray] = std::move(selection); # crash here

至此,我个人百思不得其解,按照常理来说,应该是没有问题的。在没有段错误的情况下,测试用例能够顺利通过。

刚开始以为是class Selection的右值引用问题,有内存分配/释放没有构造/析构好,或者是移动构造出现问题,经过思考和检查排除以上问题。

因此定位问题出现在map自定义的ByteArrayCompare函数上。

map定义参见文档:https://cplusplus.com/reference/map/map/

  1. template < class Key, //map::key_tpe
  2. class T, //map::mapped_type
  3. class Compare = less<Key>, //map::key_compare
  4. class Alloc = allocator<pair<const Key, T>> //map::allocator_type
  5. > class map;

由以上代码可见,map是可以自定义Compare比较函数和Alloc分配器的,此处就使用了自定义的Compare比较函数,应用于ByteArray数据类型。

题外话:unordered_map可以自定义hash和equal函数,这也体现了STL对于两种数据结构的不同实现方式,此处不再展开。

问题原因及解决方案

这里我们需要一个概念strict_weak_order(严格弱序)

本篇文章在数学和语义上阐述了严格弱序的意义,值得一看:https://zhuanlan.zhihu.com/p/378294506

抛开复杂的逻辑不谈,简单来说,该性质要求比较函数对于两个不同的key,改变输入顺序不会改变比较结果。

例:(a, b)形式输入,输出结果为a < b(假设为false),(b, a)形式输入,输出结果应该为true,若为仍false则会出现问题。

具体到我们此处的代码:此时我们已经遍历完成了a和b中较短的那个,但是对于剩余长度,没有进行比较,而是直接返回true,因此出现了上述的非严格弱序问题。

修改后代码:

  1. struct ByteArrayCompare {
  2. bool operator()(const ByteArray &a, const ByteArray &b) const {
  3. for (int i = 0; i < min(a.byteArray.size(), b.byteArray.size()); i++)
  4. {
  5. if (a.byteArray[i] != b.byteArray[i])
  6. return a.byteArray[i] < b.byteArray[i];
  7. }
  8. return a.byteArray.size() < b.byteArray.size();
  9. }
  10. typedef ByteArray value_type;
  11. };
  12. ......
  13. map<ByteArray, Selection, ByteArrayCompare> selectionMap;
  14. ......
  15. selectionMap[instanceByteArray] = std::move(selection); # crash here

至此,再进行测试后不会出现上述段错误问题,问题解决。

C++ map自定义比较函数遵守严格弱序的更多相关文章

  1. 【C++】自定义比较函数小结

    1.使用结构体grid作为map的key struct grid { int x; int y; }; (1)需要自定义比较函数operator<,不然会报错: error C2784: “bo ...

  2. std::map 自定义排序

    PS:开发中难免会用到快速检索的数据结构-map , 很多时候map自身提供的排序不能满足我们的需要或者不支持我们自定的数据结构的排序,解决办法就是自己实现排序. 这里的小案例是:我们要经用户的has ...

  3. map自定义键值类型

    map自定义键值类型 改变Map的默认比较方式 https://www.cnblogs.com/zjfdlut/archive/2011/08/12/2135698.html 大家知道,STL中的ma ...

  4. std::sort为什么保证严格弱序?

    这个问题是面试腾讯光子的时候面试官提的,当时的问题是:sort自定义comp函数能用>=吗?当时的我想comp函数只要函数签名是对的应该就没问题吧,于是答了可以.面试结束后总感觉哪里不对,耿耿于 ...

  5. oracle 自定义比较函数

    1>自定义比较函数,targetVal的值为字符串,例如:“>=90”,"2~8"等范围格式,dataVal值为字符串. create or replace funct ...

  6. C++中vector,set,map自定义排序

    一.vector排序 vector支持cmp,就类似数组,可以直接sort. #include <iostream> #include <algorithm> #include ...

  7. 对于一些stl自定义比较函数

    1.unorderd_map自定义键 自定义类型 struct my_key { int num; string name; }; 1.由于unordered_map是采用哈希实现的,对于系统的类型i ...

  8. STL中sort、priority_queue、map、set的自定义比较函数

    STL中,sort的默认排序为less,也就是说从小到大排序:priority_queue默认是less,也就说大顶堆:map默认是less,也就说用迭代器迭代的时候默认是小的排在前面:set默认是l ...

  9. 转载 从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法

    转载自:http://www.cnblogs.com/cj695/p/3863142.html sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级.本文就sort函数在 ...

  10. 【转】 从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法

    sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级.本文就sort函数在vector中的用法分为sort函数入门用法与自定义comp比较函数比较结构体这两个最基本的功能 ...

随机推荐

  1. python global函数的使用

    1.在全局变量与局部变量均存在时自定义的函数优先使用局部变量,自定义函数并不能改变全局变量的值. 查看运行结果:  2.在没有局部变量时,使用全局变量,且函数内部不能改变全局变量的值  查看运行结果: ...

  2. Hive(2)-Hive安装及简单使用

    本文的安装版本为Hive 3.1.2,且安装为单节点. 1. 安装参考及注意事项 (1) 官网:http://hive.apache.org/ (2) 上篇博客:Hadoop 3.1.3伪分布式环境安 ...

  3. C++初始化列表时,形参和实参名可以一样,编译器可以识别

    在这里初始化列表直接用age(age)即可,用this->age(age)反而会出错,C++不允许在成员初始化列表中使用this关键字来初始化类成员 class Person { public: ...

  4. 浏览器兼容 : IE 5 到 IE 9

    <!--[if IE]> <link href="ie.css" rel="stylesheet"> <![endif]--> ...

  5. [转帖]Linux下清理内存和Cache方法见下文:

    https://www.cnblogs.com/the-tops/p/8798630.html 暂时目前的环境处理方法比较简单: 在root用户下添加计划任务: */10 * * * * sync;e ...

  6. [转帖]Jmeter学习笔记(十)——元件的作用域和执行顺序

    https://www.cnblogs.com/pachongshangdexuebi/p/11582891.html jmeter是一个开源的性能测试工具,它可以通过鼠标拖拽来随意改变元件之间的顺序 ...

  7. [转帖]LTP使用和分析

    一.安装及编译流程 1.下载LTP LTP 项目目前位于 GitHub,项目地址:https://github.com/linux-test-project/ltp . 获取最新版可以执行以下命令: ...

  8. 简单定位占用最高CPU的java进程信息

    公司里面一个应用不小心点击就会导致系统性能下降很明显. 性能组的同事定位到了, 我这里以学习的态度重现一下这个过程. 1. 问题再现 产品一个非常大数据量的帮助, 点击之后就会占用非常多的cpu 因为 ...

  9. redis-shake

    https://github.com/alibaba/RedisShake/wiki/%E8%BF%90%E8%A1%8C%E7%9B%91%E6%8E%A7 redis-shake is a too ...

  10. Linux 排除某些目录下 重复jar包的方法

    Linux 排除某些目录下 取重复jar包的方法 find . -path ./runtime/java -prune -o -name '*.jar' -exec basename {} \;| s ...