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

问题背景及定位

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

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

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

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

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

struct ByteArrayCompare {
bool operator()(const ByteArray &a, const ByteArray &b) const {
for (int i = 0; i < min(a.byteArray.size(), b.byteArray.size()); i++)
{
if (a.byteArray[i] != b.byteArray[i])
return a.byteArray[i] < b.byteArray[i];
}
return true;
}
typedef ByteArray value_type;
}; ...... map<ByteArray, Selection, ByteArrayCompare> selectionMap; ...... selectionMap[instanceByteArray] = std::move(selection); # crash here

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

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

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

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

template < class Key,                                   //map::key_tpe
class T, //map::mapped_type
class Compare = less<Key>, //map::key_compare
class Alloc = allocator<pair<const Key, T>> //map::allocator_type
> 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,因此出现了上述的非严格弱序问题。

修改后代码:

struct ByteArrayCompare {
bool operator()(const ByteArray &a, const ByteArray &b) const {
for (int i = 0; i < min(a.byteArray.size(), b.byteArray.size()); i++)
{
if (a.byteArray[i] != b.byteArray[i])
return a.byteArray[i] < b.byteArray[i];
}
return a.byteArray.size() < b.byteArray.size();
}
typedef ByteArray value_type;
}; ...... map<ByteArray, Selection, ByteArrayCompare> selectionMap; ...... 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. C#对象二进制序列化优化:位域技术实现极限压缩

    目录 1. 引言 2. 优化过程 2.1. 进程对象定义与初步分析 2.2. 排除Json序列化 2.3. 使用BinaryWriter进行二进制序列化 2.4. 数据类型调整 2.5. 再次数据类型 ...

  2. OpenKruise :Kubernetes背后的托底

    本文分享自华为云社区<OpenKruise核心能力和工作原理>,作者:可以交个朋友. 一. 诞生背景 Kubernetes 自身提供的应用部署管理功能,无法满足大规模应用场景的需求,例如应 ...

  3. [转帖]聊聊字符串数据长度和nls_length_semantics参数

    字符串是我们设计数据库经常用到的类型,从传统的ASCII格式到UTF-8格式,不同应用需求对应不同的字符类型和长度配置.针对Oracle而言,最常用的类型无外乎char和varchar2两个基本类型. ...

  4. [转帖]SIMD+SSE+AVX

    http://home.ustc.edu.cn/~shaojiemike/posts/simd/   SIMD SIMD全称Single Instruction Multiple Data,单指令多数 ...

  5. [转帖]在yum安装本地rpm文件时遇到public key不正确问题

    yum错误:public.gpg.key: import read failed(2). 在yum安装本地rpm文件时遇到public key不正确问题 Downloading Packages:   ...

  6. [转帖]手摸手搭建简单的jmeter+influxdb+grafana性能监控平台

    我安装的机器是阿里云的centos8机器,其他的系统暂未验证 1.安装influxdb influxdb 下载地址https://portal.influxdata.com/downloads/,也可 ...

  7. [转帖]Linux磁盘I/O(二):使用vm.dirty_ratio和vm.dirty_background_ratio优化磁盘性能

    文件缓存是一项重要的性能改进,在大多数情况下,读缓存在绝大多数情况下是有益无害的(程序可以直接从RAM中读取数据).写缓存比较复杂,Linux内核将磁盘写入缓存,过段时间再异步将它们刷新到磁盘.这对加 ...

  8. [转帖]并发控制- sched_yield 函数

    函数说明 函数原型 #include <sched.h> int sched_yield(void); 1 2 sched_yield的作用是让出处理器,调用时会导致当前线程放弃CPU,进 ...

  9. [转帖] Linux命令拾遗-理解系统负载

    https://www.cnblogs.com/codelogs/p/16060498.html 简介# 这是Linux命令拾遗系列的第七篇,本篇主要介绍Linux中负载的概念与问题诊断方法. 本系列 ...

  10. 小程序字节转GBK及UTF8

    前段时间在Android原生搞的BLE扫码枪又要移植到小程序上来.本以为小程序不支持BLE的,结果一搜,还真支持-_-|| . 蓝牙部分问题不大,遇到的主要问题是,小程序环境如何对字符编码进行判断以及 ...