将结构插入地图时出现分段错误

Posted

技术标签:

【中文标题】将结构插入地图时出现分段错误【英文标题】:Segmentation fault when inserting struct into a map 【发布时间】:2021-12-17 01:14:45 【问题描述】:

正在填充的mapBase 参数将代表一个坐标系。我使用std::map 轻松地根据 x 排序坐标,然后配对到由内部地图排序的 y 坐标。内部映射的值稍后将保存额外的信息。现在它填充了虚拟数据。

我正在尝试将结构插入std::map,但插入时出现段错误。段错误并不总是一致的。有时插入会工作多次,然后在没有特定的次数后出现段错误。

我尝试添加调试语句,通过使用std::map::insert 函数的结果并查看结果的第二个字段来告诉我何时成功插入某些内容。这仅在没有发生段错误时才有用,并且通常总是正确的,因为我在被调用函数的开头清除了mapBase。我还尝试使用智能共享指针作为baseMap 的最终值类型,而不仅仅是结构对象本身。这并没有改变我的结果。我也尝试分配*(new cell()),结果相同。我已经提供了下面的基本代码。

主要:

    #include <map>
    #include <cmath>
    #define DEG_TO_RAD(deg) deg * M_PI / 180

    int main(int argc, char **argv)
    
      // vector of lidar range, angle pairs
      std::vector<std::pair<double, double>> lidarData 0.585, -179.41,
                                                        0.689, -151.672,
                                                        0.671, 56.6557,
                                                        0.717, 122.164,
                                                        0.611, 159.344,
                                                        0.586, 175.279;
    
      // convert returns to x, y coordinate point
      std::vector<Eigen::Matrix<double, 2, 1>> points;
      for(const auto& beam : lidarData)
      
        double angle = DEG_TO_RAD(beam.second);
        double range = beam.first;
        double x = range * cos(angle); // r * cos(theta)
        double y = range * sin(angle); // r * sin(theta)
        Eigen::Matrix<double, 2, 1> point;
        point << x, y;
        points.emplace_back(point);
      
    
      auto* newA = new A();
      newA->doSomething(points);
      
      return 0;
    

标题:

class A 
    public:
        A();

        ~A();
  
        void doSomething(std::vector<Eigen::Matrix<double, 2, 1>> &points);
  
    private:
        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();
        ;

        // define a map keyed by a x coordinate with a value of  std::map.
        // inner map is keyed by a y coordinate with a value of struct type cell.
        typedef std::map<double, std::map<double, cell>> map;
        map mapBase;
    

来源

A::A() 

A::~A() 

void A::doSomething(std::vector<Eigen::Matrix<double, 2, 1>> &points) 
    mapBase.clear();
    for (const auto &point : points) 
        auto x = point.x();
        auto y = point.y();

        auto xIt = mapBase.find(x);
        if (xIt == mapBase.end())  // coordinate does not exist if true
            std::map<double , cell> yPair;
            yPair.insert(std::make_pair(y, cell()));  // Segfault happens here
            mapBase.insert(std::make_pair(x, yPair));
         else  // x exist in map, but check if y does
            auto yIt = mapBase.at(x).find(y);
            if (yIt == mapBase.at(x).end())  // y does not exist at x if true
                mapBase.at(x).insert(std::make_pair(y, cell()));
            
        

        // Emplace values at the new cell in the map. 
        mapBase.at(x).at(y).x_m.emplace_back(x);
        mapBase.at(x).at(y).y_m.emplace_back(y);
        mapBase.at(x).at(y).hits.emplace_back(Eigen::Matrix<double, 2, 1>());
        mapBase.at(x).at(y).mean.setOnes();
        mapBase.at(x).at(y).covariance.setOnes();
    
;

A::cell::cell() 
    mean.setZero();
    covariance.setOnes();
    x_m.clear();
    y_m.clear();
    hits.clear();

在定期执行代码时,我只是在插入结构时遇到分段错误(核心转储)。使用gdb,回溯如下:

#0  std::pair<double const, cell>::pair<double, A::cell, true> (__p=..., this=<optimized out>) at /usr/include/c++/7/bits/stl_pair.h:362
#1  __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<double const, A::cell> > >::construct<std::pair<double const, A::cell>, std::pair<double, A::cell> > (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/7/ext/new_allocator.h:136
#2  std::allocator_traits<std::allocator<std::_Rb_tree_node<std::pair<double const, A::cell> > > >::construct<std::pair<double const, A::cell>, std::pair<double, A::cell> > (__a=..., __p=<optimized out>) at /usr/include/c++/7/bits/alloc_traits.h:475
#3  std::_Rb_tree<double, std::pair<double const, A::cell>, std::_Select1st<std::pair<double const, A::cell> >, std::less<double>, std::allocator<std::pair<double const, A::cell> > >::_M_construct_node<std::pair<double, A::cell> > (this=0x7fffffffd6d0, __node=0x55555585ed90) at /usr/include/c++/7/bits/stl_tree.h:626
#4  std::_Rb_tree<double, std::pair<double const, A::cell>, std::_Select1st<std::pair<double const, A::cell> >, std::less<double>, std::allocator<std::pair<double const, A::cell> > > >::_M_create_node<std::pair<double, A::cell> > (this=0x7fffffffd6d0) at /usr/include/c++/7/bits/stl_tree.h:643
#5  std::_Rb_tree<double, std::pair<double const, A::cell>, std::_Select1st<std::pair<double const, A::cell> > > std::less<double>, std::allocator<std::pair<double const, A::cell> > >::_M_emplace_unique<std::pair<double, A::cell> > (this=this@entry=0x7fffffffd6d0) at /usr/include/c++/7/bits/stl_tree.h:2351
#6  0x0000555555596ddd in std::map<double, A::cell, std::less<double>, std::allocator<std::pair<double const, A::cell> > >::emplace<std::pair<double, A::cell> > (this=0x7fffffffd6d0) at /usr/include/c++/7/bits/stl_map.h:569
#7  A::doSomething (this=this@entry=0x5555558082d0, points=std::vector with 49 elements = ...) at ...

回溯并没有使问题变得明显,但进一步的调试表明,从结构中删除均值和协方差可以使应用程序运行而不会出错。我可以将它们分成单独的参数,但在我看来这并不是正确的解决方案。也许在制作一对时复制调用会导致问题和本征参数的处理管理不善?对于理解和解决我的问题的任何帮助将不胜感激。

【问题讨论】:

能否也提供main.cpp,以便我们拥有minimal reporducible example。 什么是ndtMapBase 我为每个请求添加了一个最小可运行的主应用程序函数,并删除了 ndtMapBase,因为它不属于它。我已将问题缩小到单元结构中的特征矩阵。删除它们可以让应用程序毫无问题地运行,但不是我想要的解决方案。 @notARobot 我已经尝试过你给定的代码。而且 gcc 7.5.0 没有产生任何分段错误。您使用的是哪个编译器(带版本)?我什至在调试器中多次运行它并正常退出。我想得到分段错误,所以我可以看到是什么原因造成的。但是我无法使用 gcc 7.5.0 获得分段错误,尽管您已经写过 yPair.insert(/*with arguments here*/); 会产生分段错误。 @AnoopRana,感谢您尝试我的代码。这是在终端签入时获得的编译器版本。 gcc --version gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 所以,和你一样的版本。奇怪的是你的机器上没有这个问题。我想知道是不是因为示例中数据的大小有限。我从实际的激光雷达而不是我提供的初始化向量中获取数据。所以有更多的样本。另外,我在后面的代码中使用均值和协方差。在您的情况下,编译器可能已经为您优化了这些参数,因为它们没有在示例中使用。 【参考方案1】:

您在上面给出的代码 sn-p 中有一些错误,我已将其删除。该程序现在可以正常工作而不会出现分段错误。你可以试试这个并向我确认。

ma​​inneweighen.cpp

#include <vector>
#include <Eigen/Dense>
#include "neweigen.h"
int main(int argc, char **argv)
    
      std::vector<std::pair<double, double>> lidarData 0.585, -179.41,
                                                        0.689, -151.672,
                                                        0.671, 56.6557,
                                                        0.717, 122.164,
                                                        0.611, 159.344,
                                                        0.586, 175.279;
    
    
      std::vector<Eigen::Matrix<double, 2, 1>> points;
      for(const auto& beam : lidarData)
      
        double x = beam.first * cos(beam.second); // r * cos(theta)
        double y = beam.first * sin(beam.second); // r * sin(theta)
        Eigen::Matrix<double, 2, 1> point;
        point << x, y;
        points.emplace_back(point);
      
    
      auto* newA = new A();
      newA->doSomething(points);
      
      return 0;
    

neweigen.cpp

#include "neweigen.h"

A::A() 

A::~A() 

void A::doSomething(std::vector<Eigen::Matrix<double, 2, 1>> &points) 
    mapBase.clear();
    for (const auto &point : points) 
        auto x = point.x();
        auto y = point.y();

        auto xIt = mapBase.find(x);
        if (xIt == mapBase.end())  // coordinate does not exist if true
            std::map<double , cell> yPair;
            yPair.insert(std::make_pair(y, cell()));  // Segfault happens here
            mapBase.insert(std::make_pair(x, yPair));
         else  // x exist in map, but check if y does
            auto yIt = mapBase.at(x).find(y);
            if (yIt == mapBase.at(x).end())  // y does not exist at x if true
                mapBase.at(x).insert(std::make_pair(y, cell()));
            
        

        // Emplace values at the new cell in the map. 
        mapBase.at(x).at(y).x_m.emplace_back(x);
        mapBase.at(x).at(y).y_m.emplace_back(y);
        mapBase.at(x).at(y).hits.emplace_back(Eigen::Matrix<double, 2, 1>());
    


A::cell::cell() 
    mean.setZero();
    covariance.setOnes();
    x_m.clear();
    y_m.clear();
    hits.clear();



neweigen.h

#ifndef FILE_H
#define FILE_H
#include <vector>
#include <Eigen/Dense>
#include <map>
class A 
    public:
        A();

        ~A();
  
        void doSomething(std::vector<Eigen::Matrix<double, 2, 1>> &points);
  
    private:
        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();
        ;

        // define a map keyed by a x coordinate with a value of  std::map.
        // inner map is keyed by a y coordinate with a value of struct type cell.
        typedef std::map<double, std::map<double, cell>> map;
        map mapBase;
    ;


#endif

以上三个文件可以正常工作,不会出现任何分段错误。

【讨论】:

我将上述文件复制并粘贴到一个新项目中并运行该应用程序。我在同一位置得到相同的段错误。我在插入 yPair 之前和之后添加了调试语句作为 std::cout 我修复了最初发布的代码中的错误。在尝试删除帖子的不相关代码时,主要是复制错误,以免因不必要的代码位而使其他用户陷入困境。 @notARobot 这很奇怪,因为我使用的是完全相同的编译器(和版本)。我的 gcc 版本输出与您的完全相同。那就是我的输出为:gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0。我也在使用带有 gcc 7.5.0 的 Ubuntu 18.04。 @notARobot 在编译上述三个文件(我已经给出)时,您是否还在项目中编译了除这些文件之外的其他一些源文件?如果您正在编译一些其他文件(除了上述 3 个文件),那么原因可能来自那些其他文件。您可以尝试编译这三个确切的文件,看看它是否会产生段错误。 另外,为了确保特征矩阵没有被优化,我添加了 mapBase.at(x).at(y).mean.setOnes(); mapBase.at(x).at(y).covariance.setOnes();有了这些,即使有 std::cout 输出,应用程序也会出现段错误。【参考方案2】:

我认为您必须首先定义该对的类型: std::pair&lt;double,cell&gt; new_pair = makepair(y,cell) 然后插入到地图中。

【讨论】:

我确实尝试了您的建议,但没有得到不同的结果。这个问题肯定与在结构中具有用于均值和协方差的 Eigen 对象有关。删除它们可以使应用程序正常运行。然而,我只是不完全理解为什么会这样。

以上是关于将结构插入地图时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

删除时出现分段错误

将数据输入结构时出现分段错误[重复]

返回指针时出现分段错误[关闭]

分段错误:在 C++ 中弹出向量时出现 11

访问共享内存时出现分段错误

访问结构时出现分段错误