向std::map插入含Eigen成员的结构体时偶发段错误如何解决
这个偶发段错误是Eigen固定大小矩阵的内存对齐要求导致的:
你用到的Eigen::Matrix<double, 2, 1>、Eigen::Matrix<double, 2, 2>属于固定尺寸的可向量化类型,Eigen默认会要求16字节内存对齐,而STL容器的默认分配器无法保证存储自定义结构体时满足该对齐要求。当结构体实例的内存地址不满足对齐要求时,Eigen的SIMD优化指令访问成员就会触发段错误,因为内存地址是否对齐是随机的,所以故障表现为无规律偶发,你移除Eigen成员后问题消失也完全符合该故障特征。
你可以任选以下任意一种方案修复:
方案1:添加Eigen对齐宏(最优,不损失性能)
在cell结构体的定义末尾添加EIGEN_MAKE_ALIGNED_OPERATOR_NEW宏,该宏会重载结构体的new运算符,保证所有动态分配的cell实例都满足Eigen的对齐要求,修改后的cell定义如下:
struct cell { Eigen::Matrix<double, 2, 1> mean; Eigen::Matrix<double, 2, 2> covariance; std::vector<double> x_m {}; std::vector<double> y_m {}; std::vector<Eigen::Matrix<double, 2, 1>> hits {}; cell(); // 新增对齐宏 EIGEN_MAKE_ALIGNED_OPERATOR_NEW };
该方案不需要修改其他代码,也不会损失Eigen的SIMD计算性能,是首选方案。
方案2:关闭Eigen成员的对齐要求(简单兼容)
如果不需要SIMD优化,可以将Eigen矩阵的对齐属性设置为关闭,修改成员定义如下:
Eigen::Matrix<double, 2, 1, Eigen::DontAlign> mean; Eigen::Matrix<double, 2, 2, Eigen::DontAlign> covariance;
该方案不需要改动其他逻辑,仅对极小数值计算场景有可忽略的性能损失。
方案3:改用动态尺寸Eigen矩阵
把固定尺寸的矩阵改为动态尺寸,动态矩阵默认不需要严格对齐:
Eigen::MatrixXd mean; // 2x1 Eigen::MatrixXd covariance; // 2x2
需要注意构造函数中要指定矩阵尺寸初始化。
你当前用double作为std::map的key存在逻辑风险:浮点计算存在精度误差,理论上相同的坐标经过不同计算路径得到的x/y值可能存在极小的差异,会导致map判定为不同的key,出现预期外的多entry。建议将坐标放大固定倍数后转为整数作为key,比如保留毫米级精度的话可以用int64_t key_x = llround(x * 1000)作为外层map的key,避免精度问题。
内容的提问来源于stack exchange,提问作者notARobot

